为什么我可以在GCC中的标签后声明变量,而不能在Clang中声明?

af7jpaap  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(89)

此问题在此处已有答案

Variable declaration after goto Label(7个答案)
5天前关闭。
这篇文章是编辑并提交审查5天前.
我发现了一些在gcc下编译而不是在clang下编译的代码:

#include<stdio.h>

int main(int argc, char **argv) {
    int test = 0;

    if (test == 0) {
        goto print_five;
    } else {
        return 0;
    }

 print_five:
    int five = 6;

    printf("value of five: %d\n", five);
    return 0;
}

字符串
如果我声明变量five到函数的顶部(在test下),那么程序在两个编译器下都能编译。
在阅读了问题[1]和[2]之后,我想这可能与跳过变量声明有关,类似于需要在case语句中创建作用域。下面的示例也可以在两个编译器中编译。

print_five:
    printf("value of five: ");
    int five = 6;
    printf("%d\n", five);
    
    return 0;
print_five: ;
    int five = 6;     
    printf("value of five: %d\n", five);
    return 0;

的数据
然而,似乎情况并非如此,这与在标签后直接有一个表达式有关(也在问题[3]中解释过)。为什么这个例子可以用GCC编译而不能用Clang编译?

  1. Overkilling "crosses initialization of variable" error in C++?
  2. In C why do you need a statement after a goto label?
  3. Variable declaration after goto Label
osh3o9ms

osh3o9ms1#

在C99之前,所有的变量声明都必须在作用域块的顶部,因为声明不是语句:

{
    int a;
    int b;
    int c;

    puts("hi");
    a = 5;
    puts("ok");
}

字符串
从C99开始,你可以在函数的中间声明变量。这意味着在过去没有理由在声明之前写一个标签,显然标签从来没有被改变过允许放在声明之前(直到C23,下面更多)。有一些简单的修复方法:

// ...
    int five;
SetFive:
    five = 5;
    // ...


或者:

// ...
SetFive:
    {}
    int five = 5;
    // ...


GCC似乎是不兼容的,也就是说,编译它“不应该”编译的代码。将GCC设置为使用-std=c99甚至允许这样做,但是使用-pedantic标志将给予警告。
然而,Clang在这方面似乎是标准兼容的,并且不会编译它(即使使用-std=c2x)。
这实际上是C23中的一个特性,应该会在明年发布。我建议你在C23正式发布之前使用上面的一个工作回合。
Clang和GCC,不管是好是坏,都喜欢在默认情况下启用自己的扩展,这可以使代码在一个中编译,而不是另一个。

fsi0uk1n

fsi0uk1n2#

  • 声明 * 和 * 语句 * 在C语法中是两个独立的东西,不同的规则适用于它们。

例如,这是有效的:

if (x==0) y=1;

字符串
但这不是:

if (x==0) int z;


当涉及到标签时,在C17和更早的版本中,标签后面只能跟一个语句,而不能跟一个声明。
在C23中,语法发生了变化,当标签是复合语句的一部分(即包含在{}中)时,它后面隐含着一个null语句,因此在该版本的标准中,允许标签后面紧接着一个声明。
换句话说,在C23中:

my_label:
  int i;


是这样处理的:

my_label:
  ;
  int i;


GCC显然允许这种新语法作为扩展,即使不在C23模式下,而clang没有这种扩展。

相关问题