在下面的一段代码中
label:
int a;
goto label;
它是创建新变量还是使用相同的变量
当我们使用 goto 一次又一次调用函数时会发生什么
首先,这不会建立,因为标签必须后跟语句,而声明不是语句:
6.8.1 标记语句
句法
1 标记语句: 标识符 : 语句 case 常量表达式 : 语句 默认值 : 语句
其次,这不应该创建一个新变量。 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
这个问题也可以是“编译器如何以及何时分配局部变量?”,因为这就是这里的问题。
假设我们有这样的代码:
{
lots_of_code();
int x;
lots_of_code();
x = 5 + something;
lots_of_code_not_using_x();
return x;
}
此代码在本地范围内。在这种情况下,它看起来像函数的内部,但相同的规则将适用于 if 语句、for 循环等的内部。遇到此代码时,编译器会问自己一些问题:
x = 5 + something;
。即使这样也不一定分配,编译器也可以重新排序指令,选择首先执行lots_of_code_not_using_x();
,如果这样更有效并且不会改变代码的含义。在这种情况下,当代码到达 return 语句时分配 x。x 由标准保证从进入范围开始一直有效,直到范围结束。9899:2011 6.2.4
“5 其标识符被声明为没有链接且没有存储类说明符 static 的对象具有自动存储持续时间,某些复合文字也是如此......” /--/
“6 对于这样一个没有可变长度数组类型的对象, 它的生命周期从进入与其关联的块开始,直到该块的执行以任何方式结束。(进入封闭的块或调用函数暂停,但不结束,执行当前块。)如果递归进入块,每次都会创建一个新的对象实例。对象的初始值是不确定的。如果为对象指定了初始化,它是在块的执行中每次到达声明或复合文字时执行;否则,每次到达声明时值变得不确定。"
所以回答这个问题:不,你的 goto spaghetti 丝毫不会影响变量的分配方式。例如,如果有任何代码使用该变量,int a = 0;
那么该代码可能会一遍又一遍地执行,这取决于编译器优化整个 goto 混乱的智能程度。
否 它不会再次声明该变量并为其分配任何内存。它将使用相同的变量。
而且你的程序是错误的,标签不能在任何声明之前,它必须在语句之前,并且声明不是语句。因此,要更正它,请在标签后加一个分号。