You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中调用约定与函数实参求值顺序的区别及代码疑问

C语言函数实参的不确定输出问题

先看这段C代码:

#include <stdio.h>

void fun(int x, int y, int z)  /* 函数定义 */
{
    printf("%d %d %d\n", x, y, z);
}

int main()
{
    int a = 3;
    fun(++a, ++a, ++a);  /* 函数调用 */
    return 0;
}

这段代码在不同编译器下会产生不同输出:

  • 6 6 6
  • 6 5 4
  • 4 5 6

问题解答

1. 这种行为的核心原因:实参求值顺序未定义

这和调用约定(比如cdecl)没有关系,完全是因为C语言标准没有规定函数实参的求值顺序。

直白点说:调用fun(++a, ++a, ++a)时,编译器可以自由选择先计算哪个++a——既可以从左到右算,也可以从右到左算,甚至乱序计算,只要最终把三个参数的值传给函数就行:

  • 如果编译器先把三个++a全部计算完毕,再把结果传给函数,此时a被自增三次变成6,三个参数的值都是6,就会输出6 6 6
  • 如果编译器从右往左计算实参:先算最右侧的++a(a变成4),再算中间的++a(a变成5),最后算左侧的++a(a变成6),而函数的x对应左侧实参、y对应中间、z对应右侧,所以输出6 5 4
  • 如果编译器从左往右计算实参:先算左侧的++a(a变成4),再算中间的(a变成5),最后算右侧的(a变成6),对应函数参数就是4 5 6

2. 调用约定不影响这个问题

调用约定(比如常见的cdecl)管的是参数如何传递给函数——比如参数是从右往左压入栈,还是从左往右压栈,以及调用结束后谁来清理栈空间。但它完全不管参数的值什么时候计算。

就算你能修改调用约定,编译器依然可以自由选择实参的求值顺序,所以输出结果还是会不确定。

3. 新手避坑建议

这种在同一个函数调用里多次修改同一个变量的代码,属于C语言里的未定义行为——编译器想怎么处理就怎么处理,没有统一标准结果。

要避免这种问题,最好把参数的计算拆分出来,比如改成这样:

int main()
{
    int a = 3;
    int x = ++a;
    int y = ++a;
    int z = ++a;
    fun(x, y, z); // 此时输出固定为4 5 6,不会有任何歧义
    return 0;
}

内容的提问来源于stack exchange,提问作者Quorthon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:33:21