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;
}

这是故意的还是什么?

环境:

命令:

简短回答: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 关于静态与自动存储持续时间的描述。