最近接触到复合字面量,据我了解,下面是正确的使用方式。幸运的是,它可以在 ubuntu 上与 gcc 和 clang 一起使用。
int main() {
int *p = (int []) {1, 2};
return 0;
}
但是,我注意到另一种使用复合文字的方式,如下所示。感觉有点奇怪;这只是数组初始值设定项。以下代码使用 clang 编译良好,但使用 gcc 时失败,array initialized from non-constant array expression
。
int main() {
int p[] = (int []) {1, 2};
return 0;
}
这是故意的还是什么?
环境:
- 海湾合作委员会 (Ubuntu 4.8.2-19ubuntu1) 4.8.2
- Ubuntu clang 版本 3.5-1ubuntu1(主干)(基于 LLVM 3.5)
命令:
- gcc 测试.c
- clang 测试.c
最佳答案
简短回答:Clang 承认该程序使用了扩展
接受您编写的内容,int p[] = (int []) {1, 2};
,是一个 Clang 扩展。允许 GCC 拒绝它,因为它不是 C99 的一部分(C99 standard 引入了复合文字,可以作为引用)。
事实上,我的 Clang 版本可以在您的程序上发出警告。有趣的是,它称您的线路为“GNU 扩展”:
~ $ clang -std=c99 -pedantic t.c t.c:2:7: warning: initialization of an array of type 'int []' from a compound literal of type 'int [2]' is a GNU extension [-Wgnu-compound-literal-initializer] int p[] = (int []) {1, 2}; ^ ~~~~~~~~~~~~~~~ 1 warning generated. ~ $ clang -v Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn) Target: x86_64-apple-darwin13.4.0 Thread model: posix
长答案
行 int p[] = (int []) {1, 2};
是一个声明。它应遵循第 6.7 节中给出的语法:
6.7 Declarations
Syntax
1
declaration: declaration-specifiers init-declarator-listopt ; declaration-specifiers: storage-class-specifier declaration-specifiersopt type-specifier declaration-specifiersopt type-qualifier declaration-specifiersopt function-specifier declaration-specifiersopt init-declarator-list: init-declarator init-declarator-list , init-declarator init-declarator: declarator declarator = initializer
一切都在于initializer的定义,可以在6.7.8中找到:
6.7.8 Initialization
Syntax
1
initializer: assignment-expression { initializer-list } { initializer-list , } ……
12 The rest of this subclause deals with initializers for objects that have aggregate or union type.
…
16 Otherwise, the initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members.
6.7.8:16 中的重点是我的。基本上,这是您的程序不满足的 C99 标准部分。
关于clang 和 gcc 具有复合文字的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27734247/