c - 使用 goto 跳过变量声明?

标签 c arrays goto variable-declaration

我正在阅读 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/

相关文章:

创建具有多种元素类型的链表

c - C 中的 print 语句出错

C: 转到,指针转换和 "jump into scope of identifier with variably modified type"

php - 如何只获取数组中第一个匹配的值

javascript - 添加相同的产品 ID 但不增加其数量

c - 转到 C 中的特定地址

c++ - 我怎样才能重置我的程序? (不使用 goto)

c - 使用 Pipes 和 exec() 来控制另一个控制台应用程序

通过名称和函数指针在 C 中调用函数

c - 使用 mmap 读取非惰性文件?