for(int i=0;i<10;i++)
{
int x=0;
printf("%d",x);
{
int x=10;
printf("%d",x);
}
printf("%d",x);
}
这里我想知道变量x的内存是否会被分配两次,或者是在退出第二个块之后是否重置的值,并且内存只分配一次(对于x)?
答案 0 :(得分:5)
从C编程模型的角度来看,$(document).ready(function () {
$("#displaylog").click(function () {
$("#ramka").show();
});
});
的两个定义是两个完全不同的对象。内部块中的赋值不会影响外部块中x
的值。
此外,循环的每次迭代的定义也算作不同的对象。在一次迭代中为x
分配值不会影响后续迭代中的x
。
就实际实现而言,假设没有进行优化,有两种常见的情况。如果启用了优化,则可能会丢弃您的代码,因为编译器很容易发现循环对除x
之外的任何内容都没有影响。
两种常见的情况是
变量存储在堆栈中。在这种情况下,编译器将在堆栈上为外部i
保留一个插槽,在堆栈上为内部x
保留一个插槽。从理论上讲,它应该在作用域的开头分配插槽,并在作用域的末尾解除分配,但这只会浪费时间,所以它会在每次迭代时重用插槽。
变量存储在寄存器中。这是现代64位架构上更可能的选择。同样,编译器应该在作用域的开头“分配”(分配不是真正正确的单词)寄存器,并在结尾处“解除分配”但是,它只会在现实生活中重用相同的寄存器。
在这两种情况下,您都会注意到每次迭代的值将保留到下一次迭代,因为编译器使用相同的存储空间。但是,永远不要这样做
x
如果你编译并运行上面的(使用没有优化),你可能会发现它打印出合理的值,但是,每次绕过循环,for (int i = 0 ; i < 10 ; ++i)
{
int x;
if (i > 0)
{
printf("Before %d\n", x); // UNDEFINED BEHAVIOUR
}
x = i;
printf("After %d\n", x);
}
理论上是一个全新的对象,因此第一个x
访问未初始化的变量。这是未定义的行为,因此程序可能为您提供上一次迭代的值,因为它使用相同的存储,或者可能将您的房子烧毁并将您的女儿卖给奴隶。
答案 1 :(得分:3)
将可能删除这些未使用变量的编译器优化放在一边,答案是两次。
x
的第二个定义(技术术语)声明后其范围内的另一个定义。
但是第一个定义在该范围之后再次可见。
所以逻辑上(忘记优化)x
(x=0
)的第一个值必须保持在某个地方x=10
在游戏中#39;因此(逻辑上)需要两个存储空间。
执行下面的C程序。典型的部分输出:
A0 x==0 0x7ffc1c47a868
B0 x==0 0x7ffc1c47a868
C0 x==10 0x7ffc1c47a86c
D0 x==0 0x7ffc1c47a868
A1 x==0 0x7ffc1c47a868
B1 x==0 0x7ffc1c47a868
C1 x==10 0x7ffc1c47a86c
//Etc...
请注意,只有C点看到变量x
的值为10,而值为0的变量在D点再次可见。另请参阅两个版本的x
如何存储在不同的地址。
从理论上讲,每次迭代的地址可能不同,但我并不知道实际上是这样做的实现,因为它是不必要的。但是,如果你创建了这些非trival C ++对象,它们的构造函数和析构函数将在每个循环中被调用,但仍然驻留在相同的地址(实际上)。
人类读者显然很难隐藏这样的变量,不建议这样做。
#include <stdio.h>
int main(void) {
for(int i=0;i<10;i++)
{
int x=0;
printf("A%d x==%d %p\n",i,x,&x);
{
printf("B%d x==%d %p\n",i,x,&x);
int x=10;
printf("C%d x==%d %p\n",i,x,&x);
}
printf("D%d x==%d %p\n",i,x,&x);
}
}
答案 2 :(得分:2)
这是一个特定于实现的细节。
例如,在代码优化阶段,它可能会检测到未使用的那些。所以不会为他们分配空间。
即使某些编译器没有那个东西,那么你可以预期可能会出现两个不同的变量空间没有被分配的情况。
对于您的信息,事物括号并不总是意味着它是不同的内存或堆栈空间。这是一个范围问题。对于变量,可能是它们被分配在CPU寄存器中的情况。
所以你不能说一般的话。你可以说的是它们的范围不同。
答案 3 :(得分:1)
我希望大多数编译器都会在堆栈上使用这种类型的变量,如果需要任何内存的话。在某些情况下,CPU寄存器可能用于x中的一个或两个。两者都有自己的存储,但它依赖于编译器,无论该存储的生命周期是否与源中声明的变量范围相同。因此,例如,用于“内部”x的内存可能会在该变量超出范围之外继续使用 - 这实际上取决于编译器实现。