【问题标题】:Why does gcc/clang handle code slightly differently? (Example given)为什么 gcc/clang 处理代码略有不同? (给出的例子)
【发布时间】:2021-05-14 13:33:46
【问题描述】:

所以我在搞乱 C 代码,我注意到 gcc 和 clang 处理代码的方式。

如果我使用可变大小在文件范围内声明一个数组,clang 编译没有问题,但 gcc 会抛出错误。我的猜测是,它与 gcc/clang 中默认启用/未启用哪些编译器标志有关,但如果有人能准确地告诉我为什么会发生这种情况并可能建议一些我可以学习的在线资源,我会很高兴有关此功能的更多信息。

这里是抛出错误的代码的任意示例 -

typedef struct node{
    int data;
    struct node *next;
    struct node *prev;
}node;

const int N = 1000;
node *table[N]; // This is where the error is

int main() {
    return 0;

在没有其他标志的情况下运行 clang example.c 可以正常编译运行在没有其他标志的情况下运行 gcc example.c 会引发错误 -

example.c:9:7: error: variably modified 'table' at file scope
    9 | node *table[N];
      |       ^~~~

【问题讨论】:

  • 根据 C 标准,可变长度数组可能没有静态存储持续时间。然而,编译器可能有自己的语言扩展。如果程序编译为 C++ 程序,也没有可变长度数组。

标签: c gcc compiler-errors clang


【解决方案1】:

N 看起来像一个常数,但实际上并非如此。 const 的意思是“我发誓我不会改变这个变量的值”(否则编译器会提醒我!)。 但这并不意味着它不能以我在这个编译单元中看不到的另一种方式改变;因此这并不完全是一个常数。

gcc 似乎对标准非常严格,但使用选项-pedantic 会使clang 发出警告。

$ clang -o prog_c prog_c.c -pedantic
prog_c.c:12:14: warning: variable length array folded to constant array as an extension [-Wgnu-folding-constant]
double table[N];
             ^
1 warning generated.

$ clang -o prog_c prog_c.c -pedantic -std=c90
prog_c.c:12:13: warning: variable length arrays are a C99 feature [-Wvla-extension]
double table[N];
            ^
prog_c.c:12:8: warning: size of static array must be an integer constant expression [-Wpedantic]
double table[N];
       ^
2 warnings generated.

$ clang -o prog_c prog_c.c -pedantic -std=c99
prog_c.c:12:8: warning: size of static array must be an integer constant expression [-Wpedantic]
double table[N];
       ^
1 warning generated.

【讨论】:

  • 更一般地说,我认为 Clang 可能会将具有已知值的静态 const 限定非易失性对象(不仅在此处声明并在其他地方定义)在其他上下文中也视为编译时常量,而不仅仅是数组维度。
【解决方案2】:

根据您使用的gcc 的版本,它默认为C90(带有一些扩展名),可变长度数组不是C90 的一部分。

如果您指定-std=c99-std=c11,它应该支持VLA。

但是,根据 C 语言定义,VLA 不能具有 static 存储持续时间(就像在文件范围内声明的数组一样)。所以clang 必须将N 视为常量表达式(很像C++ 所做的),并且数组是固定长度的,而不是可变长度的。不过,到目前为止,我还没有在 clang 文档中找到任何可以表明这一点的内容。

使用选项-std=c11 -pedantic 运行两个编译器,看看是否不会出现相同的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    相关资源
    最近更新 更多