如何在variables被绕过时使用variables?

在我看来,定义总是意味着存储分配。

在下面的代码中, int i分配一个4字节(通常)存储在程序堆栈,并将其绑定到ii = 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,但是当控制通过定义时,内存不会被分配。

这里真正重要的是初始化。