在我看来,定义总是意味着存储分配。
在以下代码中,int i
在程序堆栈上分配一个4字节(通常)存储,并将其绑定到i
,i = 3
为该存储分配3。但由于goto
,定义被绕过,这意味着没有为i
分配存储空间。
我听说局部变量分配在它们所在的函数(本例中为f()
)的入口处,或者在定义点处。
但无论如何,i
如何在尚未定义的情况下使用(根本没有存储空间)?执行i = 3
时,值3分配给哪里?
void f()
{
goto label;
int i;
label:
i = 3;
cout << i << endl; //prints 3 successfully
}
答案 0 :(得分:44)
长话短说; goto
将导致运行时跳转,变量定义/声明将导致存储分配,编译时间。
编译器将查看并决定为int
分配多少存储空间,它还可以在“点击”3
时将此分配的存储空间设置为i = 3;
即使在函数开头有一个goto
,在声明/定义之前,内存位置也会存在,就像在你的例子中一样。
如果我在地上放置一根木头并且我的朋友跑了(闭着眼睛)并跳过它,那么日志仍会存在 - 即使他没有看到或感觉到它。
如果他愿意的话,他可以转身(在以后的某个时间)并将其置于火上是很现实的。他的跳跃并没有让日志神奇地消失。
答案 1 :(得分:16)
你的代码很好。如果goto
没有出现,变量就会存在。
请注意,在某些情况下您无法跳过声明:
C ++ 11 6.7声明声明[stmt.dcl]
3可以转换为块,但不能以初始化方式绕过声明。一个 程序从具有自动存储持续时间的变量不在范围内的点跳转到a 除非变量具有标量类型,具有普通默认值的类类型,否则它在范围内的点是不正确的 构造函数和一个普通的析构函数,这些类型之一的cv限定版本,或其中一个的数组 在没有初始值设定项的情况下声明前面的类型(8.5)。 [例如:
void f() { // ... goto lx; // ill-formed: jump into scope of `a' // ... ly: X a = 1; // ... lx: goto ly; // ok, jump implies destructor // call for `a' followed by construction // again immediately following label ly }
-end example]
答案 2 :(得分:9)
定义不是可执行代码。它们只是编译器的指令,让它知道变量的大小和类型。从这个意义上说,goto
语句没有绕过定义。
如果使用带有构造函数而不是int
的类,则goto
将绕过构造函数的调用,但无论如何都会分配存储。但是,类实例仍然是未初始化的,因此在定义/初始化行之前使用它来获取控件是错误的。
答案 3 :(得分:8)
在我看来,定义总是意味着存储分配。
这不正确。变量的存储由编译器在为函数创建堆栈布局时保留。 goto
只是绕过了初始化。由于您在打印前指定了一个值,一切都很好。
答案 4 :(得分:2)
流的控制与编译器在编译时保留的变量存储无关。
goto
语句仅影响对象的动态初始化。对于内置类型和POD类型,无关紧要,因为它们可以保持未初始化状态。但是,对于非POD类型,这将导致编译错误。例如,见
struct A{ A(){} }; //it is a non-POD type
void f()
{
goto label;
A a; //error - you cannot skip this!
label:
return;
}
错误:
prog.cpp: In function ‘void f()’:
prog.cpp:8: error: jump to label ‘label’
prog.cpp:5: error: from here
prog.cpp:6: error: crosses initialization of ‘A a’
在此示例中,A
是非POD类型because it has user-defined constructor,这意味着对象需要动态初始化,但由于goto
语句尝试为了省略这一点,编译器会产生错误。
请注意,只有内置类型和POD类型的对象才能保持未初始化状态。
答案 5 :(得分:1)
为简而言之,变量声明是词法,即与词汇{}
- 封闭的块有关。绑定从声明的行到块的末尾有效。它不受流量控制(goto
)的影响。
另一方面,locol(堆栈)变量的变量赋值是在控制流到达时执行的运行时操作。所以goto
会对此产生影响。
当涉及对象构建时,事情变得有点棘手,但这不是你的情况。
答案 6 :(得分:1)
i
声明的位置与编译器无关。您可以通过在int i
之前使用goto
编译代码然后比较生成的程序集来证明这一点:
g++ -S test_with_i_before_goto.cpp -o test1.asm
g++ -S test_with_i_after_goto.cpp -o test2.asm
diff -u test1.asm test2.asm
这种情况的唯一区别是源文件名(.file
)引用。
答案 7 :(得分:0)
变量的定义不为变量分配内存。它确实告诉编译器准备适当的内存空间来存储变量,但是当控制传递定义时,内存不会被分配。
这里真正重要的是初始化。