对于C函数,参数是相反的

时间:2011-11-09 07:41:06

标签: c arguments reverse function-calls

我有一个函数,它将两个矩阵A和B相乘然后打印结果。 当以两种类似的方式运行程序时,我得到了两个不同的输出。

第一

    FILE *f;
    f = fopen("in.txt","r");
    struct Mat* A = read_mat(f);
    struct Mat* B = read_mat(f);
    print_mat(mat_mul_1(A, B));

输出是

的精确乘法
  

A * B

第二

    FILE *f;
    f = fopen("in.txt","r");
    print_mat(mat_mul_1(read_mat(f), read_mat(f)));

输出是

的精确乘法
  

B * A

我想知道为什么争论被颠倒了?!

(因为'mat_mul_1'函数是一个黑盒子)

5 个答案:

答案 0 :(得分:8)

您是否期望首先评估第一个read_mat(f)

C不提供此类保证。编译器可以自由地发出代码,按照它选择的任何顺序来计算参数。

  

函数指示符的评估顺序,实际参数和   实际参数中的子表达式未指定,但有一个序列点   在实际通话之前。

答案 1 :(得分:2)

正如其他人已经指出的那样,功能参数的评估顺序是未指定的行为,因此不应该依赖。但是这里还有另一个可能是严重的问题:

函数read_mat可以访问静态资源,例如静态/全局变量,然后返回它们的值。像这样:

static int x;

int inc (void)
{
  x++;
  return x;
}

printf("%d %d", inc(), inc());

该功能的实际结果将根据评估顺序而有所不同。

(此片段取自我在聘用C程序员时使用的面试测试。我问这段代码的输出是什么,正确的答案是“2 1”“1 2”这个问题测试C程序员是否知道静态初始化和评估顺序的概念。)

答案 2 :(得分:0)

这是因为评估函数的顺序参数:

print_mat(mat_mul_1(A, B));

将调用mat_mul_1(A, B),其中A是文件中的第一个矩阵,B是第二个矩阵。 在你的第二个案例中:

print_mat(mat_mul_1(read_mat(f), read_mat(f)));

我猜测(因为标准未指定),在您的系统上,首先调用第二个read_mat(),然后调用mat_mul_1(B, A);

答案 3 :(得分:0)

原因是在最左边的read_mat(f)之前调用了最右边的B,因此你将第一个结构读入你认为是A的结构中。因此,B和{{1}}会相反。

我有点理解它,因为当它们被传递给函数时,它们被反向推入堆栈,因此它们是从右到左进行评估的。

我不确定是否有任何标准定义必须首先进行评估。

答案 4 :(得分:0)

您的代码具有未定义的行为,因为FILE指向的f被第一个和第二个read_mat(f)修改,并且这两个修改之间不存在任何序列点。