我有一个函数,它将两个矩阵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'函数是一个黑盒子)
答案 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)
修改,并且这两个修改之间不存在任何序列点。