最近在学校论坛看到一个关于C语言的问题,如下文这段代码,期待中的输出应该是5,5,但是在gcc中的结果实际是7,3,而在clang中的结果则是期望中的5,5。为什么会产生这种区别呢?其原因就在于printf("%d,%d\n", (++p)->a, (p++)->a);这句,因为在形参传参过程中,左参数(++p)->a和右参数(p++)->a不是彼此独立的,而是会相互影响,因此编译器在解释函数传参过程中,从左到右入栈还是从右到左入栈的顺序就至为关键,不凑巧的时,这个顺序在C语言标准中是没有定义的,也就是所谓的未定义行为Undefined Behavior(UB)。这个就是导致以下代码段在clang和gcc中的结果不同的原因。
这个例子告诉我们,我们在实际的编程过程中,不要使用太多“骚操作”,这样很容易造成意外的bug。我们的编码原则应该是高内聚低耦合, 一段函数应该尽可能减少其意外的影响面,比如printf函数就应该只考虑打印信息,不应该把自加的操作引入其中。另外,C/C++语言中还有其他UB行为,比如不同文件中定义的全局变量的定义顺序是未定义的,这样很容易导致一些意外之外的bug。
#include <stdio.h>
int main(void)
{
struct ks {
int a;
int* b;
}s[4], * p;
int n = 1, i;
for (i = 0; i < 4; i++) {
s[i].a = n;
s[i].b = &s[i].a;
n = n + 2;
}
p = &s[0];
p++;
printf("%d,%d\n", (++p)->a, (p++)->a);
return 0;
}