C++ 当变量的定义被忽略时,如何使用它?

C++ 当变量的定义被忽略时,如何使用它?,c++,scope,variable-declaration,C++,Scope,Variable Declaration,在我看来,定义总是意味着存储分配 在下面的代码中,int i在程序堆栈上分配一个4字节(通常)的存储器,并将其绑定到i,而i=3将3分配给该存储器。但由于goto,定义被绕过,这意味着没有为i分配存储 我听说局部变量要么在它们所在的函数的入口(f())分配,要么在定义点分配 但是,无论哪种方式,i在尚未定义的情况下如何使用(完全没有存储)?执行i=3时分配给三的值在哪里 void f() { 后藤标签; int i; 标签: i=3; 库特 在我看来,定义总是意味着存储分配 这是不正确的。当编译

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

在下面的代码中,
int i
在程序堆栈上分配一个4字节(通常)的存储器,并将其绑定到
i
,而
i=3
将3分配给该存储器。但由于
goto
,定义被绕过,这意味着没有为
i
分配存储

我听说局部变量要么在它们所在的函数的入口(
f()
)分配,要么在定义点分配

但是,无论哪种方式,
i
在尚未定义的情况下如何使用(完全没有存储)?执行
i=3
时分配给三的值在哪里

void f()
{
后藤标签;
int i;
标签:
i=3;
库特
在我看来,定义总是意味着存储分配


这是不正确的。当编译器为函数创建堆栈布局时,变量的存储是由编译器保留的。
goto
只是绕过了初始化。因为在打印之前分配了一个值,所以一切都很好。

长话短说;
goto
将导致运行时跳转,变量定义/declar优化将导致存储分配、编译时间

编译器将查看并决定为
int
分配多少存储空间,它还将使该分配的存储空间在“命中”
i=3;
时设置为
3

即使在函数开始时,在声明/定义之前有一个
goto
,该内存位置也会在那里,就像在您的示例中一样


非常愚蠢的比喻 如果我把一根圆木放在地上,我的朋友跑着(闭着眼睛)跳过它,圆木仍然会在那里——即使他没有看到或感觉到它


说他可以(以后)回头是很现实的如果他想的话,就点燃它。他的跳跃不会让日志神奇地消失。

定义不是可执行代码。它们只是编译器的指令,让编译器知道变量的大小和类型。从这个意义上说,
goto
语句不会绕过定义


如果使用带有构造函数的类而不是
int
,则构造函数的调用将被
goto
绕过,但存储将被分配。但是,类实例将保持未初始化状态,因此在其定义/初始化行获取控件之前使用它是一个错误。

使其更安全t、 变量声明是词法性的,即与词法
{}
-封闭块有关。绑定从声明行到块末尾是有效的。它不受流控制(
goto
)的影响

另一方面,locol(堆栈)变量的变量分配是在控制流到达时执行的运行时操作。因此
goto
对其有影响


当涉及到对象构造时,事情会变得有点棘手,但这不是您的情况。

变量的定义不会为变量分配内存。它会告诉编译器准备适当的内存空间来存储变量,但当控件传递定义时,内存不会分配


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

您的代码很好。如果
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
}
-[结束示例]


i
声明的位置与编译器无关。您可以通过在
goto
之前使用
int i
编译代码,然后在生成的程序集之后进行比较来证明这一点:

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
)引用。

流的控制与编译器在编译时保留的变量存储无关

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类型,这意味着需要动态初始化对象,但由于
goto
语句试图跳过此操作,编译器会生成错误,这是应该的


请注意,只有内置类型和POD类型的对象才能保持未初始化状态。

您混淆了代码的编译顺序和控制流无法抵制对明喻的向上投票!对我来说,它仍然是bizare。如果未执行行
int i;
,则逻辑希望未定义i!编译器知道这一点指令不会被删除,所以在我的头脑中,我应该跳过,而不是定义。但是,显然C++的标准规则是不同的……在另一个跳过代码< >一个A/A代码>一个类的情况下,在编译时会崩溃。这是所有的变量。如果我们把int i改为STD::?goto是否对其传递的对象强制执行构造函数调用?
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’