【发布时间】:2014-01-14 21:26:57
【问题描述】:
这是 C 代码快照:
int* f(int x) {
static int y;
y = x * x;
return &y;
}
float* g(float x) {
static float y;
y = x * x;
return &y;
}
int main(void) {
printf("*f(1)=%d\n", *f(1));
printf("*f(2)=%d\n", *f(2));
printf("*f(1) + *f(2)=%d\n", *f(1) + *f(2));
printf("*g(1.0)=%f\n", *g(1.0));
printf("*g(2.0)=%f\n", *g(2.0));
printf("*g(1.0) + *g(2.0)=%f\n", *g(1.0) + *g(2.0));
return 0;
}
输出是:
*f(1)=1
*f(2)=4
*f(1) + *f(2)=5
*g(1.0)=1.000000
*g(2.0)=4.000000
*g(1.0) + *g(2.0)=8.000000
而且我并不真正理解 f() 和 g() 的双重行为。首先,我怀疑这是编译器问题,但 BCC 或 GCC 提供相同的输出。
*f(1) + *f(2) 的输出不应该等于*g(1.0) + g(2.0) 吗? (55.0 或88.0)
【问题讨论】:
-
这是未指定或未定义的行为;这里没有明确定义的评估顺序。
-
我相信奥利是正确的。更明确地说,这将取决于在加法发生之前如何存储值。如果你执行
*g(1.0),那么*g(2.0)在存储值之前,你会加上4.0 + 4.0 = 8.0(记住,每个指针指向同一个静态变量的值)。否则,如果您执行*g(1.0)并将其值存储在寄存器中,然后执行*g(2.0)并添加结果,您将得到1.0 + 4.0 = 5.0。 -
related question from the C faq;基本上,如果要保证函数调用的顺序,则需要将函数调用放在单独的语句中。
-
我认为这在 C 2011 中可能是未定义的行为,但在 C 1999 中不是。众所周知,在 C 1999 中,如果表达式同时修改并分别使用对象的值序列点。但这在这里不会发生,因为函数调用中有序列点,调用中完整表达式的结尾。因此,只是未指定调用发生的顺序。在 C 2011 中,6.5 2 表示如果副作用相对于不同的副作用或值计算未排序,则行为未定义。这似乎适用于这段代码。