【问题标题】:Does goto construct create new variablegoto 构造是否创建新变量
【发布时间】:2012-06-07 10:15:56
【问题描述】:

在下面这段代码中

label:
int a;
goto label;

它是创建新变量还是使用相同的变量
还有当我们使用 goto 一次又一次调用函数时会发生什么

【问题讨论】:

  • 只是为了澄清一下,您使用此代码是否有任何编译器错误?
  • This 是我问的原因..
  • 只是为了概念我问这是否会导致内存泄漏
  • 顺便说一句,请注意使用 goto 通常被认为是不良的编程习惯,因为它们会使代码路径难以遵循。

标签: c goto


【解决方案1】:

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

6.8.1 带标签的语句

语法

1 标记语句:
        标识符 : 语句
        case constant-expression : 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

【讨论】:

    【解决方案2】:

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

    假设我们有这样的代码:

    {
      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();,如果这样更有效并且不会改变代码的含义。在这种情况下,x 在代码到达 return 语句时被分配。

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

    "5 一个对象,其标识符被声明为没有链接,也没有 存储类说明符 static 具有自动存储持续时间,如 做一些复合文字...” /--/

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

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

    【讨论】:

      【解决方案3】:

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

      而且你的程序是错误的,标签不能在任何声明之前,它必须在语句之前,并且声明不是语句。所以要更正它,请在标签后加一个分号。

      【讨论】:

      • 我想你的意思是在标签之后,即label: ;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-23
      • 1970-01-01
      • 2014-02-06
      • 1970-01-01
      • 2015-05-06
      • 2016-03-21
      • 1970-01-01
      相关资源
      最近更新 更多