如何在variables被绕过时使用variables?
在我看来,定义总是意味着存储分配。
在下面的代码中, int i
分配一个4字节(通常)存储在程序堆栈,并将其绑定到i
, i = 3
分配3该存储。 但是由于goto
,定义被绕过,这意味着没有为i
分配的存储空间。
我听说局部variables被分配在函数的入口f()
在这种情况下是f()
),或者在定义的地方。
但无论如何, i
还没有被定义的时候如何使用(根本没有存储)呢? 执行i = 3
时,三个值分配到哪里?
void f() { goto label; int i; label: i = 3; cout << i << endl; //prints 3 successfully }
长话短说; goto
会导致运行时跳转,variables定义/声明会导致存储分配,编译时间。
编译器会看到并决定为int
分配多less存储空间,这也会使得当“敲击” i = 3;
时这个分配的存储空间将被设置为i = 3;
。
即使在你的函数的开头有一个goto
,在声明/定义之前,那个内存位置就会在那里,就像你的例子一样。
非常愚蠢的比喻
如果我在地上放了一个木头,而且我的朋友(闭上眼睛)跑过去,那么木头仍然会在那里 – 即使他没有看见或感觉到它。
如果他愿意的话,他可以转过头来(如果他想的话)放在火上,这是现实的。 他的跳跃不会使日志神奇消失。
你的代码很好。 变化生活的地方,只要goto
不在那里。
请注意,有些情况下您不能跳过声明:
C ++ 11 6.7声明语句[stmt.dcl]
3可以将其转换为块,但不能绕过具有初始化的声明。 从具有自动存储持续时间的variables不在范围内的点跳转到在范围内的点跳转的程序是格式不正确的,除非variables具有标量types,具有简单的默认构造函数和简单的析构函数的类types,这些types之一的cv限定版本,或者前面types之一的数组,并声明没有初始值设定项(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 }
– 例子]
定义不是可执行代码。 它们只是编译器的指令,让它知道variables的大小和types。 从这个意义上说,这个定义并没有被goto
声明所绕过。
如果你使用一个带有构造函数的类来代替int
,构造函数的调用会被goto
绕过,但是存储将被分配。 类实例将保持未初始化,但是,因此在定义/初始化行获取控件之前使用它是一个错误。
在我看来,定义总是意味着存储分配。
这是不正确的。 编译器在创build函数的堆栈布局时保留该variables的存储空间。 goto
只是绕过了初始化。 由于您在打印之前分配了一个值,所以一切正常。
stream的控制与编译器在编译时保留的variables的存储无关。
goto
语句只影响对象的dynamic初始化。 对于内置types和PODtypes,没关系,因为它们可以保持未初始化。 但是,对于非PODtypes,这会导致编译错误。 例如看到这个
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'
看到这里: http : //ideone.com/p6kau
在这个例子中, A
是一个非PODtypes, 因为它有用户定义的构造函数 ,这意味着对象需要dynamic初始化,但由于goto
语句试图跳过这个,所以编译器会产生错误。
请注意,只有内置types和PODtypes的对象可以保持未初始化。
为了简短起见,variables声明是词法的, 也就是说,涉及词汇{}
封闭的块。 绑定从声明的行到块的结尾是有效的。 它不受stream量控制( goto
)的影响。
另一方面,locol(堆栈)variables的variables赋值是在控制stream程到达时执行的运行时操作。 所以goto
对此有影响。
当对象构造涉及时,情况会变得更加棘手,但这不是你的情况。
i
的声明的位置与编译器无关。 你可以通过在goto
之前用int i
编译你的代码来certificate这一点,然后再比较生成的程序集:
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
)引用。
variables的定义不会为variables分配内存。 它告诉编译器准备适当的内存空间来存储variables,但是当控制通过定义时,内存不会被分配。
这里真正重要的是初始化。