gcc 为什么这些数组声明(C89-C90)没有编译错误?

vxbzzdmp  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(221)

我想说明数组不能用C89或C90中的长度变量来定义。
我在Windows上使用的GCC来自TDM GCC:

C:\TDM-GCC-64\bin> .\gcc.exe --version
gcc.exe (tdm64-1) 10.3.0

我的编译选项包括:gcc.exe -Wall -g -ansi -save-temps -c
我试探着:

int main()
{
    int i;
    int tab[i];

    tab[0] = 10;

    return 0;
}

但它编译得很好:

gcc.exe -Wall -g -ansi -save-temps -c main.c -o main.o
gcc.exe -o Sandbox.exe main.o  
main.c:6:9: warning: variable 'tab' set but not used [-Wunused-but-set-variable]
    6 |     int tab[i];
      |         ^~~
main.c:6:5: warning: 'i' is used uninitialized in this function [-Wuninitialized]
    6 |     int tab[i];
      |     ^~~
Output file is bin\Debug\Sandbox.exe with size 196.89 KB

然后道:

int test(int i)
{
    int tab[i];
    tab[0] = 10;
    return 0;
}

也编译:

main.c: In function 'test':
main.c:5:9: warning: variable 'tab' set but not used [-Wunused-but-set-variable]
    5 |     int tab[i];
      |         ^~~
Output file is bin\Debug\Sandbox.exe with size 196.90 KB

或者:

int main()
{
    volatile int i;
    int tab[i];

    tab[0] = 10;

    return 0;
}

只有这一点是不编译的:
第一个
我错过了什么?谢谢!

v09wglhw

v09wglhw1#

变长数组是GCC的一个扩展,它与标准是“兼容的”。如果你想严格遵守标准,也就是说,你想在使用扩展时得到一个消息,添加-pedantic选项(和-pedantic-errors表示错误)。
美国政府采购委员会文件:https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Variable-Length.html#Variable-Length,https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Warning-Options.html#Warning-Options。

j2cgzkjk

j2cgzkjk2#

gcc默认的标准符合性很差,它默认为lax C一致性+ GNU扩展,相当于-std=gnu89(当前版本默认为-std=gnu17)。
当你输入-ansi时,它并不意味着一致模式,而是和-std=c89一样的东西,“lax C89模式”。这个编译器选项可能会禁用一些GNU扩展......也许......同时保留其他的。-std=c89-std=gnu89之间的区别和gcc的其他部分一样,被记录的很少。我们可以read the unfriendly manual,它说:
例如,-std=c90会关闭GCC中与ISO C90不兼容的某些功能,如asm和typeof关键字,但不会关闭在ISO C90中没有意义的其他GNU扩展
gcc甚至在C99之前就支持可变长度数组作为扩展,所以关闭GNU选项应该会禁用它们,但事实并非如此......据我所知,没有官方文档说明-std=c89关闭了哪些特性,或者至少我找不到。
需要注意的是,-std=c89/-ansi本身并不能将gcc推入一致模式!要做到这一点,您需要执行-std=c89 -pedantic-std=c89 -pedantic-errors。之后,您将得到如下诊断:
错误:ISO C90禁止使用可变长度数组'tab'
当结合使用这两个选项进行编译时,gcc可能是所有编译器中最符合标准的。

相关问题