clang 和 gcc 具有复合文字的不同行为
clang and gcc different behavior with compound literal
最近接触到复合字面量,据我了解,下面是正确的使用方法。幸运的是,它可以在 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;
}
这是故意的还是什么?
环境:
- gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
- Ubuntu clang 版本 3.5-1ubuntu1(主干)(基于 LLVM 3.5)
命令:
- gcc test.c
- 叮当声test.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标准部分。
复合文字在 C99 和 C++ 中具有不同的行为。
在 C++ 中,它只有一个表达式存储持续时间,没有自动持续时间。如果这是在C++模式下编译的,那么它不会工作,因为复合文字对象在表达式完成后消失。
这或许可以解释@cremno 关于静态与自动存储持续时间的描述。
最近接触到复合字面量,据我了解,下面是正确的使用方法。幸运的是,它可以在 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;
}
这是故意的还是什么?
环境:
- gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
- Ubuntu clang 版本 3.5-1ubuntu1(主干)(基于 LLVM 3.5)
命令:
- gcc test.c
- 叮当声test.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标准部分。
复合文字在 C99 和 C++ 中具有不同的行为。
在 C++ 中,它只有一个表达式存储持续时间,没有自动持续时间。如果这是在C++模式下编译的,那么它不会工作,因为复合文字对象在表达式完成后消失。
这或许可以解释@cremno 关于静态与自动存储持续时间的描述。