g中的goto和自动变量初始值设定项

时间:2012-07-12 08:13:31

标签: c

在教程中说

如果使用goto语句跳转到块的中间,则不会初始化该块中的自动变量。

然后在下面的代码中,如果我可以访问/声明,那么为什么它没有被初始化?

int main()
{
   goto here;
   {
     int i=10;
     here:
      printf("%d\n",i);
   }
   return 0;
}

ps:输出是一些垃圾值。

6 个答案:

答案 0 :(得分:9)

你的问题背后没有逻辑“如果可以访问i,为什么......”。能够“访问i”不是支持或反对任何事情的论据。它只是意味着printf语句与i的范围相同。但是,由于您跳过了初始化程序,因此该变量未初始化(正如您的教程所说)。

读取未初始化的变量是未定义的行为,因此您的程序格式不正确。

变量i的内存已经在编译时被搁置,因为已知变量存在于内部块中。正如您可能想象的那样,内存不会动态分配。它已经存在,但由于goto,它永远不会被设置为任何确定的。

经验法则:不要跨越初始化器。

答案 1 :(得分:2)

变量在声明它们的范围内可见(在本例中为{}之间),而不管该范围内语句的执行顺序如何。 goto绕过i的初始化,这意味着在调用printf()时它具有未定义的值。

答案 2 :(得分:1)

考虑另一个明显的情况:

int main()
{
    int i; //i is declared, but not initialized
    goto here;
    {
       i=10;//i is initialized 
       here: //you've skipped the initialization
       printf("%d\n",i);//and got garbage
    }
return 0;
}

在你的情况下:

int main()
{

    goto here;
    {
       //printf("%d\n",i);  // i does not exist here yet
       int i; //from here until the end of the scope variable i exists
       i=10;  // i exists here and smth is written into it
   here:  // i exists here
       printf("%d\n",i); // i exists here and it's value is accessed
    }
return 0;
}

所以,int i = 5;那真是两件事。一个是声明,并且不能通过任何东西跳过,包括goto(很像开放新的范围也不会受到影响。你已经跳到了范围的中间,但范围已经存在)。其次是操作分配,因为它是正常操作(程序流程),所以可以跳过goto或“中断”或“继续”,或“返回”

答案 3 :(得分:0)

C编译器将解析源文件,并“记录”任何变量初始化 到达时

printf("%d\n", i)

它将知道变量i已经存在并且他应该能够使用它,因为它在范围内。
执行空间在主函数调用之后,在执行main()中的任何代码之前,为堆栈上的i变量保留。

答案 4 :(得分:0)

因为语言标准是这样说的:

6.7.8初始化

<强>语义

如果没有显式初始化具有自动存储持续时间的对象,则其值是不确定的。

J.2未定义的行为

在以下情况下,行为未定义:

具有自动存储持续时间的对象的值在不确定时使用。

6.8.4.2开关语句

示例在人工程序片段中

switch (expr)
{
  int i = 4;
  f(i);
  case 0:
    i = 17;
    /* falls through into default code */
  default:
    printf("%d\n", i);
}

标识符为i的对象存在自动存储持续时间(在块内)但从未初始化,因此如果控制表达式具有非零值,则对printf函数的调用将访问不确定的值。同样,无法访问对函数f的调用。

答案 5 :(得分:-1)

C允许您访问地址空间中的任何内容,无论它是否实际初始化。有时像崩溃或显示垃圾一样工作,有时它会打印出有用的东西,但它都是未定义的行为。方便的技巧,但是打破你的程序的好方法,所以不要认为只是得到一个结果意味着你的技巧。