goto构造是否创建新变量

时间:2012-06-07 10:15:57

标签: c goto

在下面的代码中

label:
int a;
goto label;

是否创建新变量或使用相同的变量
当我们使用goto

一次又一次地调用函数时会发生什么

3 个答案:

答案 0 :(得分:2)

首先,这不会构建,因为标签后面必须跟一个语句,而声明不是声明:

6.8.1标记语句

语法

1    labeled-statement:
        identifier : statement
        case constant-expression : statement
        default : statement

其次,这个不应该创建一个新变量。 goto不会引入新范围,因此不会在每次迭代时创建a的新实例。即使在 引入新范围的情况下,例如

for (;;) {int a; ... }

a的空间(通常)只分配一次;即使逻辑您正在为每个循环迭代处理a的新实例,物理您(通常)回收相同的内存位置。任何物理上为a 创建新空间而不回收先前空间的编译器将会被IMO严重破坏。

只是为了咯咯笑,我写了以下内容:

#include <stdio.h>

#ifdef __STDC_VERSION__
  #if __STDC_VERSION__ >= 199901L
    #define C99
  #endif
#endif

int main(void)
{
label:
  #ifdef C99
    ;
  #endif
  int a;
  printf("&a = %p\n", (void *) &a); 
  goto label;

  return 0; 
}

使用gcc -std=c99 -pedantic -Wall -Werror构建它,我得到以下输出:

&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c
&a = 0xbf98ad8c

答案 1 :(得分:1)

否它不会再次声明该变量并为其分配任何内存。它将使用相同的变量。

而且你的程序错了,标签不能在任何声明面前,它必须在声明和声明之前不是声明。所以为了纠正它,在标签后加上一个半冒号。

答案 2 :(得分:1)

这个问题也可能是“编译器如何以及何时分配局部变量?”,因为这是问题所在。

假设我们有这样的代码:

{
  lots_of_code();

  int x;

  lots_of_code();

  x = 5 + something;

  lots_of_code_not_using_x();

  return x;
}

此代码位于本地范围内。在这种情况下,它看起来像函数的内部,但相同的规则将适用于if语句的内部,for循环等。遇到此代码时,编译器会问自己一些问题:

  • 我是否需要分配x或者我可以优化它吗?不,在这种情况下,如果不改变代码的含义,就不能优化x。
  • 分配x的最佳位置在哪里?这完全是CPU特定的:x可以在堆栈上或CPU寄存器中分配等。
  • 我什么时候分配x?对此的答案总是:“当它第一次使用时”。在这种情况下,在执行行x = 5 + something;之前肯定不会分配x。即使这样也不一定分配,编译器也可以重新排序指令,首先选择执行lots_of_code_not_using_x();,如果它更有效并且不改变代码的含义。在这种情况下,当代码到达return语句时分配x。

x保证标准从进入范围一直有效,直到范围结束。 9899:2011 6.2.4

  

“5声明标识符没有链接且没有链接的对象   存储类说明符static具有自动存储持续时间,如   做一些复合文字......“/ - /

     

“6对于没有可变长度数组类型的对象,   其生命周期从进入与其关联的块延伸,直到该块的执行以任何方式结束。 (进入   封闭的块或调用函数暂停但不结束,   执行当前块。)如果以递归方式输入块,   每次都会创建一个新的对象实例。初始值   对象是不确定的。如果指定了初始化   对象,每次声明或复合时执行   在块的执行中达到了字面值;否则,价值   每次达到声明时都变得不确定。“

所以回答这个问题:不,你的goto spaghetti不会影响变量的分配方式。如果有任何使用该变量的代码,例如int a = 0;那么该代码可能会一遍又一遍地执行,这取决于编译器如何智能地优化掉整个goto混乱。