c - 意外的静态变量地址行为

标签 c variables static

这是 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) 吗? (5 5.08 8.0)

最佳答案

我相信 Oli 是正确的。更明确地说,这将取决于在添加发生之前如何存储值。如果执行*g(1.0),那么在存储值之前执行*g(2.0),您将添加4.0 + 4.0 = 8.0 (请记住,每个指针都指向同一个静态变量的地址)。否则,如果您执行 *g(1.0) 并将其值存储在寄存器中,然后执行 *g(2.0) 并将结果相加,您将得到 1.0 + 4.0 = 5.0

所以,实际上,这取决于编译器如何将其写入机器代码。考虑以下伪 x86 程序集(为简单起见,我们使用 int 而不是 float):

push 1 
call g ; First call to g(1);
add esp, 4 ; Pop value 1
mov ebx, eax ; Save our pointer
push 2
call g ; Call to g(2)
add esp, 4 ; Pop value 2 -- Remember that eax == ebx, now (they point to same address)
mov eax, [eax] ; Forget the pointer, store the value (4).
mov ebx, [ebx] ; Do the same thing, value is 4 since they point to same place
add eax, ebx   ; Add our two values. 4 + 4 = 8
ret

反之,考虑以下

push 1 
call g ; First call to g(1);
add esp, 4 ; Pop value 1
mov ebx, [eax] ; Save the value at the pointer (1).
push 2
call g ; Call to g(2)
add esp, 4 ; Pop value 2 -- Remember that eax == ebx, now (they point to same address)
mov eax, [eax] ; Forget the pointer, store the value (4).
add eax, ebx   ; Add our two values. 4 + 1 = 5
ret

因此,在不显式存储其值的情况下使用这样的共享变量时,指令顺序非常重要。通常,指令顺序将取决于编译器以及某些优化标志是打开还是关闭。此外,任何一个结果都可以被认为是一个合理的假设,没有硬语义来控制它,因为它没有真正违反标准(更多信息:请参阅下面 Eric 的回复):它是取消引用每个函数的返回值并添加结果。因此,如果编译器优化重新排序事情的完成方式,就会导致意外结果。

关于c - 意外的静态变量地址行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21124371/

相关文章:

c - 如何在 CMake 文件中为 C/Ada 代码集成 gnatmake/gnatbind/gnatlink?

c++ - Makefile:将库添加到另一个项目

java - 如何在不调用构造函数的情况下从另一个类获取变量?

c - 将第一个数字与第二个数字交换,将第二个数字与第三个数字交换,等等

c++ - 为什么 malloc 总是返回 NULL

c - 无法通过指针更改字符串文字中的字符

javascript - 如何正确释放JavaScript变量的内存?

python - python中如何将两个变量的内容变成一个可调用的变量名?

bash - 局部变量 `unset` 的奇怪行为

java - java中static指的是什么