欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C语言编程笔记丨为什么f(i = -1, i = -1)是未定义行为?

程序员文章站 2022-09-30 10:29:45
最近在读order of evaluation violations,其中的一个例子使我很困惑。 1)如果对一个标量对象的副作用相对于对这个标量对象的另一个副作用是无序的,那么这是未定义行为。 在这段代码中,很明显 i 是一个标量对象。 算术类型(3.9.1),枚举类型,指针类型,指针成员类型(3. ......

最近在读,其中的一个例子使我很困惑。

1)如果对一个标量对象的副作用相对于对这个标量对象的另一个副作用是无序的,那么这是未定义行为。

//代码片段

f(i=-1,i=-1);//undefined behavior 未定义行为

在这段代码中,很明显 i 是一个标量对象。

算术类型(3.9.1),枚举类型,指针类型,指针成员类型(3.9.2),空指针类型和被const或volatile修饰的类型(3.9.3)等统称为标量类型。

从这句话中我看不出上面那句代码有什么分歧的地方。我认为不论第一个参数还是第二个参数先执行,i最终都是-1,并且两个参数的值都是-1。

有人能解释清楚这些吗?

 

最佳答案:

既然运算是无序的,也就不能说分配任务的指令不能交错执行。也许会选择最佳的方式去运行,由cpu的架构来决定。引用下面这句话来说明:

如果a在b之前是无序的并且b在a之前是无序的,那么存在两种可能性:

(1)预估a和b是无序的:它们可能以任意的顺序运行并且可能会重叠(在一个线程的执行中,编译器可能会交错组织包含a和b的cpu指令)。

(2)预估a和b是无法确定的顺序:它们可能以任意顺序运行但是一定不会重叠。或者a在b执行之前完成或者b在a执行之前完成。下一次执行同样的语句时,执行的顺序有可能是相反的。

假设运算执行后,把-1存进一个内存地址,就这个行为自身而言,这似乎并不会引发任何问题。但是如果一个指令和另一个指令交错执行操作同一个内存地址,你不能说编译器不会把这些指令优化成一个独立的具有同样效果的指令集,这样就会出错了。

例如,假想把内存清零然后再递减是最高效的。现在开始值是-1,然后就是:

f(i=-1,i=-1)

也许会变成:

clear i //清空 i

clear i //清空 i

decr i //递减 i

decr i //递减 i

现在i是-2。

这也许是一个假的例子,但可能是真的。

博主是一个有着7年工作经验的架构师,对于c++,自己有做资料的整合,一个完整学习c语言c++的路线,学习资料和工具。可以进我的q群7418,18652领取,免费送给大家。希望你也能凭自己的努力,成为下一个优秀的程序员!另外博主的微信公众号是:c语言编程学习基地,欢迎关注!