6

我有一个将两个矩阵 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' 函数是一个黑盒子)

4

5 回答 5

8

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

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

函数指示符、实际参数和实际参数中的子表达式的求值顺序未指定,但在实际调用之前有一个序列点。

于 2011-11-09T07:43:00.507 回答
2

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

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

static int x;

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

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

函数的实际结果将根据评估顺序而有所不同。

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

于 2011-11-09T09:54:45.810 回答
0

这是因为对函数的 order 参数进行了评估:

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);

于 2011-11-09T07:44:11.253 回答
0

原因是最右边的在最read_mat(f)左边的之前被调用,因此您正在将第一个结构读入您假定的B. 因此AB是相反的。

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

我不确定是否有任何标准定义必须首先评估的内容。

于 2011-11-09T07:45:23.290 回答
0

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

于 2011-11-09T07:48:43.483 回答