C - 局部变量具有相同的地址和值
C - Local variables have the same address and value
我有以下 C 代码:
void testA() {
int x = 56;
printf("Address of x = 0x%x - Value of x = %d\n",&x,x);
}
void testB() {
int y;
printf("Address of y = 0x%x - Value of y = %d\n",&y,y);
}
int main() {
testA();
testB();
return 0;
}
打印结果如下:
Address of x = 0x61fdec - Value of x = 56
Address of y = 0x61fdec - Value of y = 56
为什么testB()
的局部变量y
和testA()
的局部变量x
有相同的地址并且也继承了它的值?它们甚至不在同一范围内,其中 none 是一个全局变量。
这是因为,在 TestA
函数调用结束时,x
超出范围并被清除。之后,创建 y
并分配相同的内存位置。
注意以下代码中的变量具有相同的作用域,但它们具有不同的地址:
#include <stdio.h>
void test() {
int x = 56;
printf("Address of x = 0x%x - Value of x = %d\n",&x,x);
int y;
printf("Address of y = 0x%x - Value of y = %d\n",&y,y);
}
int main() {
test();
return 0;
}
C 2018 6.2.4 2 说:
The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it…
在没有 static
或 extern
的函数内声明其标识符的对象具有 自动存储持续时间 。 C 实现自动为它们保留内存并自动释放保留。
生命周期从对象所在的块开始执行(如果它不是可变长度数组)或执行到声明(如果它是可变长度数组)时开始。
当testA
的主体开始执行时,内存被保留给x
。
然后你在x
.
中输入56
然后函数returns,块x
停止执行。所以不再为它预留内存
没有人来清理那段记忆。无论是在现实世界还是在电脑里,你妈妈都不会跟着你打扫卫生。
有人可能会出现并使用那段记忆。他们应该自己初始化它,但是,如果他们不这样做,他们可能会看到您放入该内存中的内容。
当testB
开始执行时,为y
保留内存。由于这些预留的组织方式,很容易与之前为 x
预留的内存相同。那么出现在 y
中的值可能与您在 x
.
中输入的值相同
当您打开优化时,编译器可能会重新设计程序并消除这种影响。或者它可能不会。
因为他们可以。
C 标准只要求 distinct 同时退出的对象具有不同的(读取不相等的)地址。在您的情况下,变量 x
和 y
的 none 可以同时有效。因此实现可以为它们分配相同的地址。
这个问题有两个完全不同的答案。
一个是为对象分配地址是 C 实现的工作。这不是您的工作,也可以说与您无关。在非常广泛的范围内,允许 C 实现为您的对象分配任何地址,因此您不应该对它分配的任何内容感到惊讶。一个新的范围内对象恰好与刚超出范围的另一个对象具有相同的地址?好吧,那是“任何东西”。并非不可能,不足为奇,不是你的问题。
同理,未初始化变量的初始值是不确定的。你不知道它可能是什么;它可能是任何东西。它恰好与前一个函数的前一个变量具有相同的值?再一次,那是“任何东西”,这并非不可能,不足为奇,这不是你的问题。
现在,我知道,那不是你的问题。您在想,新变量恰好与前一个变量具有完全相同的地址和完全相同的值,这不仅仅是巧合。你在想象它一定意味着什么。
所以这是第二个答案。
许多 C 实现将函数的局部变量存储在 堆栈 上。每个变量的地址通常定义为函数调用的 堆栈帧 内的偏移量。当一个函数returns时,它的栈帧被弹出栈,而当调用下一个函数时,它的栈帧将占据相同的、新释放的栈部分。因此,如果前一个函数和下一个函数都有相同类型的相同变量,那么它们相对于堆栈帧的偏移量可能是相同的。因此,如果前一个和下一个堆栈帧位于堆栈中的同一位置,则这些堆栈帧中的变量也将位于相同的地址。
此外,当一个函数 returns 时,虽然它的堆栈帧从堆栈中弹出,但这 不 意味着任何东西实际上都被清除了。当一个新调用的函数分配了它的堆栈帧时,此时也没有任何东西被清除。因此,如果一个函数有一个没有显式初始化的局部变量,它的实际初始值——我们所说的值是“不确定的”——实际上将是堆栈上剩余的任何位模式,由堆栈帧为的最后一个函数留下那里。因此,如果最后一个函数在相同的堆栈帧偏移量处具有相同的变量,你可能会发现,你瞧,下一个函数的相同偏移量变量将开始包含与前一个函数的变量具有相同的值。
但这显然都是偶然事件和机会,不是你可以依赖的任何东西。您所听说的关于局部变量 not 保留其值(更不用说另一个函数的值)的说法是完全正确的。如果您不希望函数 testB
中的 y
之类的未初始化变量开始时包含令人惊奇的值,则将其初始化为适当的、意味深长的值,这意味着 testB
.
我有以下 C 代码:
void testA() {
int x = 56;
printf("Address of x = 0x%x - Value of x = %d\n",&x,x);
}
void testB() {
int y;
printf("Address of y = 0x%x - Value of y = %d\n",&y,y);
}
int main() {
testA();
testB();
return 0;
}
打印结果如下:
Address of x = 0x61fdec - Value of x = 56
Address of y = 0x61fdec - Value of y = 56
为什么testB()
的局部变量y
和testA()
的局部变量x
有相同的地址并且也继承了它的值?它们甚至不在同一范围内,其中 none 是一个全局变量。
这是因为,在 TestA
函数调用结束时,x
超出范围并被清除。之后,创建 y
并分配相同的内存位置。
注意以下代码中的变量具有相同的作用域,但它们具有不同的地址:
#include <stdio.h>
void test() {
int x = 56;
printf("Address of x = 0x%x - Value of x = %d\n",&x,x);
int y;
printf("Address of y = 0x%x - Value of y = %d\n",&y,y);
}
int main() {
test();
return 0;
}
C 2018 6.2.4 2 说:
The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it…
在没有 static
或 extern
的函数内声明其标识符的对象具有 自动存储持续时间 。 C 实现自动为它们保留内存并自动释放保留。
生命周期从对象所在的块开始执行(如果它不是可变长度数组)或执行到声明(如果它是可变长度数组)时开始。
当testA
的主体开始执行时,内存被保留给x
。
然后你在x
.
然后函数returns,块x
停止执行。所以不再为它预留内存
没有人来清理那段记忆。无论是在现实世界还是在电脑里,你妈妈都不会跟着你打扫卫生。
有人可能会出现并使用那段记忆。他们应该自己初始化它,但是,如果他们不这样做,他们可能会看到您放入该内存中的内容。
当testB
开始执行时,为y
保留内存。由于这些预留的组织方式,很容易与之前为 x
预留的内存相同。那么出现在 y
中的值可能与您在 x
.
当您打开优化时,编译器可能会重新设计程序并消除这种影响。或者它可能不会。
因为他们可以。
C 标准只要求 distinct 同时退出的对象具有不同的(读取不相等的)地址。在您的情况下,变量 x
和 y
的 none 可以同时有效。因此实现可以为它们分配相同的地址。
这个问题有两个完全不同的答案。
一个是为对象分配地址是 C 实现的工作。这不是您的工作,也可以说与您无关。在非常广泛的范围内,允许 C 实现为您的对象分配任何地址,因此您不应该对它分配的任何内容感到惊讶。一个新的范围内对象恰好与刚超出范围的另一个对象具有相同的地址?好吧,那是“任何东西”。并非不可能,不足为奇,不是你的问题。
同理,未初始化变量的初始值是不确定的。你不知道它可能是什么;它可能是任何东西。它恰好与前一个函数的前一个变量具有相同的值?再一次,那是“任何东西”,这并非不可能,不足为奇,这不是你的问题。
现在,我知道,那不是你的问题。您在想,新变量恰好与前一个变量具有完全相同的地址和完全相同的值,这不仅仅是巧合。你在想象它一定意味着什么。 所以这是第二个答案。
许多 C 实现将函数的局部变量存储在 堆栈 上。每个变量的地址通常定义为函数调用的 堆栈帧 内的偏移量。当一个函数returns时,它的栈帧被弹出栈,而当调用下一个函数时,它的栈帧将占据相同的、新释放的栈部分。因此,如果前一个函数和下一个函数都有相同类型的相同变量,那么它们相对于堆栈帧的偏移量可能是相同的。因此,如果前一个和下一个堆栈帧位于堆栈中的同一位置,则这些堆栈帧中的变量也将位于相同的地址。
此外,当一个函数 returns 时,虽然它的堆栈帧从堆栈中弹出,但这 不 意味着任何东西实际上都被清除了。当一个新调用的函数分配了它的堆栈帧时,此时也没有任何东西被清除。因此,如果一个函数有一个没有显式初始化的局部变量,它的实际初始值——我们所说的值是“不确定的”——实际上将是堆栈上剩余的任何位模式,由堆栈帧为的最后一个函数留下那里。因此,如果最后一个函数在相同的堆栈帧偏移量处具有相同的变量,你可能会发现,你瞧,下一个函数的相同偏移量变量将开始包含与前一个函数的变量具有相同的值。
但这显然都是偶然事件和机会,不是你可以依赖的任何东西。您所听说的关于局部变量 not 保留其值(更不用说另一个函数的值)的说法是完全正确的。如果您不希望函数 testB
中的 y
之类的未初始化变量开始时包含令人惊奇的值,则将其初始化为适当的、意味深长的值,这意味着 testB
.