在C语言中,函数参数的计算顺序是标准未定义的(直到C99)。参数可以从左到右、从右到左或以其他任何顺序计算(由编译器或架构决定)。
void fn(int a, int b) { /* ... */ } int x = 1; fn(x++, x++); // x++ 和 x++ 的计算顺序未定义!
"C中的函数参数计算顺序是什么,编写代码时可以依赖这个顺序吗?"
一个常见错误是认为参数是从左到右计算的(类似于表达式)。实际上,每个函数调用都是由编译器(和平台)决定的。
void foo(int a, int b, int c); int x = 1; foo(x++, x++, x++); // 结果取决于参数的计算顺序
真正的答案是:不能依赖 — 行为未定义!
故事
在一个多平台的产品中,程序员编写了
push(stack, stack->size++, data);。在大多数平台上运行良好,但在某个平台上栈的大小在传递数据之前增加,而在另一平台上则在之后增加。数据经常“丢失”或地址不正确,错误很少被发现,调试非常困难。
故事
在网络协议库中,日志记录功能被调用时使用了会递增统计计数器的表达式参数。生成的统计报告不正确:不同客户端的计数器索引不同,因为执行顺序不如预期。
故事
在设备控制接口中,初始化函数在参数内部传递带有递增的指针和偏移量(例如
init(ptr++, cnt++);)。在某些处理器上,硬件初始化正确,而在其他处理器上则出现失败,原因被长时间追查至硬件,尽管问题出在C代码不正确上。