您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

C++表达式和语句有啥区别

时间:2021-07-21 15:15:30  来源:  作者:CPP编程

历史上

在最早的通用编程语言中,如FORTRAN,这种区别是非常清楚的。在FORTRAN中,一个语句是一个执行单位,是你做的一件事。它不被称为 "行 "的唯一原因是有时它跨越了很多行。一个表达式本身不能做任何事情,你必须把它分配给一个变量。在FORTRAN中表达式是一个错误,因为它不做任何事情。你必须对这个表达式做一些事情。

FORTRAN并没有我们今天所知的语法,这个语法是和Backus-Naur Form(BNF)一起发明的,是Algol-60定义的一部分。当时,语义上的区别("有一个值 "与 "做某事")被载入了语法中:一种是表达式,另一种是语句,解析器可以将它们区分开来。

后来语言的设计者模糊了这种区别:他们允许表达式做事情,也允许语句有一个值。C语言的设计者意识到,如果允许你评估一个表达式并丢弃其结果,就不会造成任何伤害。在C语言中,每一个语法表达式都可以通过在结尾处加一个分号而成为一个语句。

表达式和语句的这种模糊性出现在所有的C语言衍生语言中(C、C++、C#和JAVA),它们仍然有一些语句(如while),但几乎允许任何表达式作为语句使用。

这两个 "语法类别" 会导致重复劳动。例如,C语言有两种形式的条件,if语句和?:表达式。

有时,人们希望有这样的重复:例如,在标准的C语言中,只有语句可以声明一个新的局部变量,但这种能力非常有用,GNU C编译器提供了一个GNU扩展(语句表达式),使表达式也可以声明一个局部变量。

而其他语言的设计者不喜欢这种重复,他们很早就看到,如果表达式可以有副作用,也可以有值,那么语句和表达式之间的语法区别就不是那么有用了,所以他们把它去掉了。Haskell、Icon、Lisp和ML都是没有语句的语言,它们只有表达式。即使是类似结构的循环和条件形式也被认为是表达式,而且它们有值。

一些区别描述

  • 表达式会进行计算产生一个结果(结果的三个方面:值、类型和值类别),而语句不会。
  • 表达式可以在语句中使用,但不能反过来使用。不过,一个例外是lambda表达式,它表示一个函数,因此可以包含函数可以包含的任何内容,除非该语言只允许有限的lambdas。
  • 两种类型都可以组合,但只要类型匹配,大多数表达式都可以任意组合。每种类型的语句都有自己的组合其他语句的方式。表达式可以使用操作符“水平地”组合成更大的表达式,而语句只能通过一个接一个地编写或使用块结构来“垂直地”组合。
  • 命令式语言(Fortran, C, Java,…)强调语句来构造程序,而表达式则是一种事后思考。函数式语言强调表达式。纯函数式语言具有比语句更强大的表达式。
  • 一个例子
#include <IOStream>
int main() {
    int x;
    x = 2, 3;
    std::cout << x << std::endl;
    return 0;
}

结果:2

#include <iostream>
int f(){ return 2, 3; }
int main() {
    int x;
    x = f();
    std::cout << x << std::endl;
    return 0;
}

结果:3

分析如下:

x=2,3是一个表达式,表达式中逗号操作符“,”的优先级低于赋值运算符“=”。所以这个表达式语句相当于(x=2),3;

return 2, 3;是返回语句,return不属于表达式,只有2,3为表达式。逗号操作符是从左到右计算,所以2,3表达式结算结果是3。

Can programming be liberated from the von Neumann style?: a functional style and its algebra of programs(编程能从冯·诺依曼风格中解放出来吗?:一种函数式风格及其程序代数)

FP,是John Backus创立的支持函数级编程范式的编程语言。它允许消去命名变量。这种语言是在Backus的1977年图灵奖获奖演讲论文《编程可以从冯诺依曼风格中解放出来吗?程序的函数式风格及其代数》中提出的。这篇论文点燃了对函数式语言研究的兴趣,最终导致了现代函数式语言,但不是Backus曾希望的函数级范式。
在他的这篇图灵奖论文中,Backus描述了FP风格与基于lambda演算的语言有着如何不同:
FP系统基于了对叫做泛函形式的一组固定的组合形式的利用。它们加上简单的定义,就是从现存函数建造新函数的唯一方式;它们不使用变量或替代规则,并且它们成为程序相关的代数的运算操作。FP系统的所有函数都是一种类型的:它们映射对象到对象之上并总是接受一个单一实际参数。
FP自身在学术界之外从未被大量使用。在1980年代,Backus创建了后继语言FL,它也保持为研究项目。

冯诺依曼风格是一种语句与表达式的编程风格,而函数式编程风格是建立在使用组合形式创建程序的基础上。

C++表达式

表达式(expression)是运算符和它们的操作数的序列,它指定一项计算。表达式的求值可以产生一个结果(比如 2+2 的求值产生结果 4),也可能产生副作用(比如i = 5; i++;的副作用i变成6)。

常见运算符

赋值

自增
自减

算术

逻辑

比较

成员访问

其他

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :

特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象,并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)

初等表达式:任何运算符的操作数都可以是其他的表达式或初等表达式。

初等表达式包括以下各项:

  1. 字面量(例如 2 或 "Hello, world")
  2. 标识表达式,包括经过适当声明的无限定的标识符(例如 n 或 cout)或者经过适当声明的有限定的标识符(例如 std::string::npos)
  3. lambda 表达式 (C++11)
  4. 折叠表达式 (C++17)
  5. requires 表达式 (C++20)
  6. 括号中的任何表达式也被归类为初等表达式

常量表达式:定义能在编译时求值的表达式。这种表达式能用做非类型模板实参、数组大小,并用于其他要求常量表达式的语境(上下文)

不求值表达式:运算符 typeid、sizeof、noexcept 、 decltype (C++11 起)和requires 表达式 的操作数是不求值表达式,因为这些运算符仅查询其操作数的编译期性质。因此,std::size_t n = sizeof(std::cout << 42); 不进行控制台输出。不求值的运算数被当做完整表达式 (C++14 起),所以要符合表达式的一些要求。

弃值表达式:弃值表达式是仅用来实施其副作用的表达式。从这种表达式计算的值被舍弃。这样的表达式包括任何表达式语句的完整表达式,内建逗号运算符的左边的实参,以及转型到类型 void 的转型表达式的实参。运算符delete是弃值表达式,因其返回值是void类型。

求值顺序:求值任何表达式的任何部分,包括求值函数参数的顺序都是未说明的(除了一些例外)。编译器能以任何顺序求值任何操作数和其他子表达式,并且可以在再次求值同一表达式时选择另一顺序。

#include <cstdio>
int a() { return std::puts("a"); }
int b() { return std::puts("b"); }
int c() { return std::puts("c"); }
void z(int, int, int) {}
int main() {
    z(a(), b(), c());       // 允许全部 6 种输出排列
    return a() + b() + c(); // 允许全部 6 种输出排列
}

可能的输出:

b
c
a
c
a 
b

优先级和结合性:优先级 指定包含多个运算符的表达式中的运算顺序。 结合性指定是否在包含多个具有相同优先级的运算符的表达式中,将操作数分组在其左侧或右侧的一个(a=b=c)。

结合性规定对于一元运算符是冗余的,只为完备而给出:一元前缀运算符始终从右到左结合(delete ++*p 为 delete(++(*p)))而一元后缀运算符始终从左到右结合(a[1][2]++ 为 ((a[1])[2])++)。

优先级和结合性是编译时概念,与求值顺序无关,后者是运行时概念。

优先级

运算符

描述

结合性

1

::

作用域解析

从左到右

2

a++ a--

后缀自增与自减

type() type{}

函数风格转型

a()

函数调用

a[]

下标

. ->

成员访问

3

++a --a

前缀自增与自减

从右到左

+a -a

一元加与减

! ~

逻辑非和逐位非

(type)

C 风格转型

*a

间接(解引用)

&a

取址

sizeof

取大小[注 1]

co_await

await 表达式 (C++20)

new new[]

动态内存分配

delete delete[]

动态内存分配

4

.* ->*

成员指针

从左到右

5

a*b a/b a%b

乘法、除法与余数

6

a+b a-b

加法与减法

7

<< >>

逐位左移与右移

8

<=>

三路比较运算符(C++20 起)

9

< <=

分别为 < 与 ≤ 的关系运算符

> >=

分别为 > 与 ≥ 的关系运算符

10

== !=

分别为 = 与 ≠ 的相等性运算符

11

a&b

逐位与

12

^

逐位异或(互斥或)

13

|

逐位或(可兼或)

14

&&

逻辑与

15

||

逻辑或

16

a?b:c

三元条件[注 2]

从右到左

throw

throw 运算符

co_yield

yield 表达式 (C++20)

=

直接赋值(C++ 类默认提供)

+= -=

以和及差复合赋值

*= /= %=

以积、商及余数复合赋值

<<= >>=

以逐位左移及右移复合赋值

&= ^= |=

以逐位与、异或及或复合赋值

17

,

逗号

从左到右

C++语句

语句(statement)是依序执行的 C++ 程序片段。任何函数体都是语句的序列。

类型:

  1. 表达式语句(expression statement);
  2. 复合语句(compound statement);
  3. 选择语句(selection statement);
  4. 循环语句(iteration statement);
  5. 跳转语句(jump statement);
  6. 声明语句(declaration statement);
  7. try 块;
  8. atomic 与 synchronized 块(TM TS)。


Tags:C++   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
一、编程语言1.根据熟悉的语言,谈谈两种语言的区别?主要浅谈下C/C++和PHP语言的区别:1)PHP弱类型语言,一种脚本语言,对数据的类型不要求过多,较多的应用于Web应用开发,现在好多互...【详细内容】
2021-12-15  Tags: C++  点击:(17)  评论:(0)  加入收藏
函数调用约定(Calling Convention),是一个重要的基础概念,用来规定调用者和被调用者是如何传递参数的,既调用者如何将参数按照什么样的规范传递给被调用者。在参数传递中,有两个很...【详细内容】
2021-11-30  Tags: C++  点击:(19)  评论:(0)  加入收藏
一、为什么需要使用内存池在C/C++中我们通常使用malloc,free或new,delete来动态分配内存。一方面,因为这些函数涉及到了系统调用,所以频繁的调用必然会导致程序性能的损耗;另一...【详细内容】
2021-11-17  Tags: C++  点击:(37)  评论:(0)  加入收藏
C++编程中,你是否有为 我到底该写个struct还是class 而苦恼过?如果你到现在还不知道该如何选择,那么请求继续阅读,下文或许能给你些建议。问题的产生C++语言继承了 C语言的 stru...【详细内容】
2021-10-18  Tags: C++  点击:(61)  评论:(0)  加入收藏
C++在C的面向过程概念的基础上提供了面向对象和模板(泛型编程)的语法功能。下面以一个简单实例(动态数组的简单封装,包括下标的值可以是任意正数值,并提供边界检查)来说明C++是如...【详细内容】
2021-10-18  Tags: C++  点击:(49)  评论:(0)  加入收藏
0 前言Hello,大家好,欢迎来到『自由技艺』的 C++ 系列专题。代码重用,尽可能避免冗余代码是程序员的一项必备技能,今天就来给大家介绍其中一种:函数装饰器。在设计模式中,与它对应...【详细内容】
2021-09-28  Tags: C++  点击:(75)  评论:(0)  加入收藏
今天我们就来聊一聊 C++ 中的异常机制吧。在学校期间,我们很少会用得上异常机制。然而,工作之后,很多时候却不得不引入异常机制。因为一般情况下,使用函数的返回值来确定函数的...【详细内容】
2021-09-26  Tags: C++  点击:(181)  评论:(0)  加入收藏
一、内存泄漏(memory leak)内存泄漏(memory leak)是指由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存...【详细内容】
2021-09-03  Tags: C++  点击:(104)  评论:(0)  加入收藏
stack容器#include <iostream>using namespace std;#include <stack>//容器头文件void test(){stack<int>p;p.push(100);p.push(1000);p.push(100);while(!p.empty()){cout<...【详细内容】
2021-08-17  Tags: C++  点击:(81)  评论:(0)  加入收藏
stl 常用遍历算法(for_each transform)示例代码(结论在结尾!!!!)#include<iostream>using namespace std;#include"vector"#include"map"#include"string"#include"list"#in...【详细内容】
2021-08-13  Tags: C++  点击:(89)  评论:(0)  加入收藏
▌简易百科推荐
一、简介很多时候我们都需要用到一些验证的方法,有时候需要用正则表达式校验数据时,往往需要到网上找很久,结果找到的还不是很符合自己想要的。所以我把自己整理的校验帮助类分...【详细内容】
2021-12-27  中年农码工    Tags:C#   点击:(0)  评论:(0)  加入收藏
引言在学习C语言或者其他编程语言的时候,我们编写的一个程序代码,基本都是在屏幕上打印出 hello world ,开始步入编程世(深)界(坑)的。C 语言版本的 hello world 代码:#include <std...【详细内容】
2021-12-21  一起学嵌入式    Tags:C 语言   点击:(10)  评论:(0)  加入收藏
读取SQLite数据库,就是读取一个路径\\192.168.100.**\position\db.sqlite下的文件<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/...【详细内容】
2021-12-16  今朝我的奋斗    Tags:c#   点击:(21)  评论:(0)  加入收藏
什么是shellshell是c语言编写的程序,它在用户和操作系统之间架起了一座桥梁,用户可以通过这个桥梁访问操作系统内核服务。 它既是一种命令语言,同时也是一种程序设计语言,你可以...【详细内容】
2021-12-16  梦回故里归来    Tags:shell脚本   点击:(16)  评论:(0)  加入收藏
一、编程语言1.根据熟悉的语言,谈谈两种语言的区别?主要浅谈下C/C++和PHP语言的区别:1)PHP弱类型语言,一种脚本语言,对数据的类型不要求过多,较多的应用于Web应用开发,现在好多互...【详细内容】
2021-12-15  linux上的码农    Tags:c/c++   点击:(17)  评论:(0)  加入收藏
1.字符串数组+初始化char s1[]="array"; //字符数组char s2[6]="array"; //数组长度=字符串长度+1,因为字符串末尾会自动添&lsquo;\0&lsquo;printf("%s,%c\n",s1,s2[2]);...【详细内容】
2021-12-08  灯-灯灯    Tags:C语言   点击:(46)  评论:(0)  加入收藏
函数调用约定(Calling Convention),是一个重要的基础概念,用来规定调用者和被调用者是如何传递参数的,既调用者如何将参数按照什么样的规范传递给被调用者。在参数传递中,有两个很...【详细内容】
2021-11-30  小智雅汇    Tags:函数   点击:(19)  评论:(0)  加入收藏
一、问题提出问题:把m个苹果放入n个盘子中,允许有的盘子为空,共有多少种方法?注:5,1,1和1 5 1属同一种方法m,n均小于10二、算法分析设f(m,n) 为m个苹果,n个盘子的放法数目,则先对...【详细内容】
2021-11-17  C语言编程    Tags:C语言   点击:(46)  评论:(0)  加入收藏
一、为什么需要使用内存池在C/C++中我们通常使用malloc,free或new,delete来动态分配内存。一方面,因为这些函数涉及到了系统调用,所以频繁的调用必然会导致程序性能的损耗;另一...【详细内容】
2021-11-17  深度Linux    Tags:C++   点击:(37)  评论:(0)  加入收藏
OpenCV(Open Source Computer Vision Library)是一个(开源免费)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android、ios等操作系统上,它轻量级而且高效---由一系列...【详细内容】
2021-11-11  zls315    Tags:C#   点击:(50)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条