注册 登录
编程论坛 C语言论坛

初来乍到,先拜个山头!

辛或 发布于 2023-04-17 04:02, 245 次点击
小生初来宝地,没什么拜见各位大侠,先写几个好玩的例子耍耍。这些例子的代码是很危险的,根本原因是:C++对子表达式的求值顺序没有定义,这使得一些表达式的结果取决于具体的C++实现(编译器)。我只写了几个,欢迎大侠补充。

例子一:


int x = f()+g();

这里不能假定f()和g()哪个先调用,有的编译器会先调用g()。

例子二:


int i = 1;
a[i] = ++i;

这里不能假定结果是a[1]=2。有的编译器先对子表达式:++i求值,那就是a[2]=2。

例子三:


int s = 5;
int x = (s + 1) * (++s);

这里不能假定结果是x=6*6=36。有的编译器先对子表达式:++s求值,那就是x=7*6=42。

例子四:

int i=1;
int x = i+1==++i ? 1 : 0;

这里x的值是1还是0,取决于子表达式i+1和++i哪个先求值。要是先对子表达式:++i求值,那x的值是0,要是先对i+1求值,那x的值就是1。

例子五:

int a[] = {1, 2};
int i = 0;
int x = a[i] << ++i;

这里x的值是什么?根据先对a[i]求值还是先对++i求值,可能是2,可能是4。

但是,逗号(,)表达式是从左到右求值的。比如:

i=0,i+=1,i*=2;

结果是:

i=2;


[此贴子已经被作者于2023-4-17 07:38编辑过]

4 回复
#2
pvm20002023-04-17 07:39
解决不确定问题的方法,是将步骤确定化。
将一个语句拆成多个语句就成了
#3
辛或2023-04-17 07:50
以下是引用pvm2000在2023-4-17 07:39:04的发言:

解决不确定问题的方法,是将步骤确定化。
将一个语句拆成多个语句就成了

其实这里的问题是:要确定子表达式的求值顺序对整个表达式的结果无关。

比如,例子1要是拆分成:

int x;
int f_x = f(x);
int g_x = g(x);
x= f_x + g_x;

就显得有点傻......

[此贴子已经被作者于2023-4-17 08:09编辑过]

#4
rjsp2023-04-17 08:41
但是,你的例子中大部分属于「未定义行为」,而非「实现定义行为」


int i = 1;
a[i] = ++i;
这里不能假定结果是a[1]=2。有的编译器先对子表达式++i求值,那就是a[2]=2。
为例,输出2是可能的,但输出3、输出4、输出5、……都是可能的;甚至这段代码格式化掉你的硬盘也是符合C语言规定的。
先对哪个子表达式进行评估确实属于「实现定义行为」,但如果这两个子表达的副作用冲突,则属于「未定义行为」
详见:https://zh.
#5
辛或2023-04-17 08:55
以下是引用rjsp在2023-4-17 08:41:43的发言:

但是,你的例子中大部分属于「未定义行为」,而非「实现定义行为」


为例,输出2是可能的,但输出3、输出4、输出5、……都是可能的;甚至这段代码格式化掉你的硬盘也是符合C语言规定的。
先对哪个子表达式进行评估确实属于「实现定义行为」,但如果这两个子表达的副作用冲突,则属于「未定义行为」
详见:https://zh.


这些例子的代码是很危险的,根本原因是:C++对子表达式的求值顺序没有定义
意思就是,表达式行为未定义吧?
1