我正在阅读 K.N.King 撰写的 C Programming - A Modern Approach 以学习 C 编程语言,其中指出 goto
语句不能跳过可变长度数组声明.
但现在的问题是:为什么goto
跳转允许跳过定长数组声明和普通声明?更准确地说,根据 C99 标准,这些示例的行为是什么?当我测试这些案例时,似乎声明实际上没有被跳过,但这是正确的吗?声明可能被跳过的变量是否可以安全使用?
1.
goto later;
int a = 4;
later:
printf("%d", a);
2.
goto later;
int a;
later:
a = 4;
printf("%d", a);
3.
goto later;
int a[4];
a[0] = 1;
later:
a[1] = 2;
for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
printf("%d\n", a[i]);
最佳答案
我想在没有血淋淋的内存布局细节的情况下解释这一点(相信我,当使用 VLA 时,它们会变得非常血腥;有关详细信息,请参阅@Ulfalizer 的回答)。
所以,最初,在 C89 中,必须在 block 的开头声明所有变量,如下所示:
{
int a = 1;
a++;
/* ... */
}
这直接暗示了一件非常重要的事情:一个 block ==一组不变的变量声明。
C99 改变了这一点。在其中,您可以在 block 的任何部分声明变量,但声明语句与常规语句仍然不同。
事实上,要理解这一点,您可以想象所有变量声明都被隐式移动到声明它们的 block 的开头,并使其对前面的所有语句不可用。
这仅仅是因为一个 block == 一组声明规则仍然成立。
这就是为什么您不能“跳过声明”的原因。声明的变量仍然存在。
问题是初始化。它不会“移动”到任何地方。因此,从技术上讲,对于您的情况,可以认为以下程序是等效的:
goto later;
int a = 100;
later:
printf("%d", a);
和
int a;
goto later;
a = 100;
later:
printf("%d", a);
如你所见,声明还在,跳过的是初始化。
这不适用于 VLA 的原因是它们不同。简而言之,这是因为这是有效的:
int size = 7;
int test[size];
与所有其他声明不同,VLA 的声明在声明它们的 block 的不同部分表现不同。事实上,一个 VLA 可能有完全不同的内存布局,这取决于它声明的位置。你只是不能将它“移动”到你刚刚跳过的地方之外。
您可能会问,“好吧,那为什么不让声明不受 goto
的影响”?好吧,你仍然会遇到这样的情况:
goto later;
int size = 7;
int test[size];
later:
您实际上希望它做什么?..
因此,禁止跳过 VLA 声明是有原因的 - 通过简单地完全禁止它们来处理上述情况是最合乎逻辑的决定。
关于c - 使用 goto 跳过变量声明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29880836/