C 赋值语句的求值顺序

标签 c compilation cross-compiling

我遇到过跨平台代码在基本赋值语句上表现不同的情况。

一个编译器首先评估左值,其次评估右值,然后评估赋值。

另一个编译器先做右值,再做左值,然后再赋值。

如果左值影响右值的值,这可能会产生影响,如下例所示:

struct MM {
    int m;
}
int helper (struct MM** ppmm ) { 
    (*ppmm) = (struct MM *) malloc (sizeof (struct MM)); 
    (*ppmm)->m = 1000;
    return 100;
}

int main() { 
    struct MM mm = {500};
    struct MM* pmm = &mm
    pmm->m = helper(&pmm);
    printf(" %d %d " , mm.m , pmm->m);
}

上面的示例,行 pmm->m = helper(&mm);,取决于求值的顺序。如果先计算左值,则 pmm->m 等同于 mm.m,如果先计算右值,则 pmm->m 等同于在堆上分配的 MM 实例。

我的问题是是否有一个 C 标准来确定评估的顺序(没有找到),或者每个编译器都可以选择要做什么。 还有其他类似的陷阱我应该注意吗?

最佳答案

= 表达式求值的语义包括

The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.

(C2011,6.5.16/3;已强调)

强调的条款明确允许您在不同编译器编译时观察到程序行为的差异。此外,unsequenced 意味着,即使在程序的同一构建的不同运行中,评估也可以以不同的顺序发生。如果多次调用出现无序计算的函数,则允许在同一程序执行期间的不同调用期间以不同顺序进行计算。

这已经回答了问题,但重要的是要看到更大的图景。修改对象或调用这样做的函数是副作用 (C2011, 5.1.2.3/2)。因此,这项关键规定开始发挥作用:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

(C2011, 6.5/2)

被调用的函数具有修改存储在 main() 的变量 pmm 中的值的副作用,赋值的左侧操作数的评估涉及使用 pmm 的值计算值,这些是未排序的,因此行为未定义。

不惜一切代价避免未定义的行为。因为您的程序的行为是未定义的,所以不限于您观察到的两种选择(以防万一还不够糟糕)。 C 标准对其可能执行的操作没有任何限制。相反,它可能会崩溃,将硬盘的分区表归零,或者,如果您有合适的硬件,则可以召唤鼻恶魔。或其他任何东西。其中大部分不太可能,但最好的观点是,如果您的程序有未定义的行为,那么您的程序是错误的

关于C 赋值语句的求值顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37597855/

相关文章:

c - 当我尝试在我自己以外的机器上运行时,Kruskal 的最小生成树程序 (C) 出现段错误(核心转储)错误

c - sched_setaffinity 和 glibc - 交叉编译

c - GtkImage 上的 GdkDrawingArea

c - pthread_rwlock_rdlock() 和 pthread_rwlock_wrlock()

c - 如果有的话,编译器什么时候会在指针取消引用优化方面保持保守?

c - 如何编译 ruby​​ 示例?

python - 如何将python 3.4.3脚本编译为exe?

performance - 有哪些编译速度快的编译型编程语言?

openssl - 在裸机上交叉编译 openssl

macos - 在 Mac 上为 iPhone 交叉编译?