我发现一些代码可以在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

推荐答案

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

{
    int a;
    int b;
    int c;

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

从C99开始,您可以在函数中间声明变量.这意味着在过go 没有真正的理由在声明之前写标签,而且显然标签从来没有改变过,允许放在声明之前(直到C23,下面更多).有一些简单的修复方法:

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

或者:

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

GCC似乎是不兼容的,也就是说,编译代码它"不应该.将GCC设置为使用-std=c99甚至允许这样做,但是使用-pedantic标志将给出警告.

Clang在这方面似乎是标准兼容的,并且不会编译它(即使是-std=c2x).

这实际上是C23的一项功能,应该会在明年发布.我建议你在C23正式发布之前,使用上面的一轮工作.

不管是好是坏,Clang和GCC都喜欢在默认情况下启用自己的扩展,这可以使代码在一个中编译,而不是在另一个中编译.

C++相关问答推荐

理解没有返回语句的递归C函数的行为

为什么在函数内部分配内存空间时需要添加符号?

为什么我一直收到分段错误?

为什么该函数不将参数值保存到数据 struct 中?

C-使用指针返回修改后的整数数组

在Linux上使用vscode和lldb调试用Makefile编译的c代码

在for循环中指向数组开头之前

如何在GDB中查看MUSL的源代码

如何使用唯一数字对整型进行分区

类型定义 struct 与简单的类型定义 struct

为什么realloc函数在此代码中修改变量?

将回调/基于事件的C API转换为非回调API

如何读取程序中嵌入的数据S自己的ELF?

从C中的函数返回静态字符串是不是一种糟糕的做法?

OMP并行嵌套循环

在git补丁中自动添加C的宏

与指针的原始C数组或C++向量<;向量<;双>>;

使用共享变量同步多线程 C 中的函数

Makefile - 将 .o 文件放入子文件夹中

创建 makefile 来编译位于不同目录中的多个源文件