3

最近遇到复合文字,据我了解,以下是正确的使用方法。幸运的是,它适用于 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 测试.c
  • 铿锵测试.c
4

2 回答 2

6

简短回答:Clang 承认该程序使用了扩展

接受你写的int p[] = (int []) {1, 2};,是一个 Clang 扩展。允许 GCC 拒绝它,因为它不是 C99 的一部分(C99 标准引入了复合文字,可以用作参考)。

事实上,我的 Clang 版本可以对你的程序发出警告。有趣的是,它将您的行称为“GNU 扩展”:

~ $ clang -std=c99 -pedantic tc
tc:2:7: 警告:从复合中初始化类型为“int []”的数组
      'int [2]' 类型的文字是 GNU 扩展
      [-Wgnu-compound-literal-initializer]
  int p[] = (int []) {1, 2};
      ^ ~~~~~~~~~~~~~~~
生成 1 个警告。
~ $ 铿锵 -v
Apple LLVM 5.1 版(clang-503.0.40)(基于 LLVM 3.4svn)
目标:x86_64-apple-darwin13.4.0
线程模型:posix

长答案

该行int p[] = (int []) {1, 2};是一个声明。它应该遵循第 6.7 节中给出的语法:

6.7 声明

句法

1

宣言:
    声明说明符 init-declarator-list opt ;

声明说明符:
    存储类说明符 声明说明符opt
    类型说明符 声明说明符opt
    类型限定符 声明说明符opt
    函数说明符 声明说明符opt

初始化声明器列表:
    初始化声明器
    初始化声明器列表,初始化声明器

初始化声明器:
    声明者
    声明器 = 初始化器

一切都取决于initializer的定义,可以在 6.7.8 中找到:

6.7.8 初始化

句法

1

初始化器:
    赋值表达式
    {初始化列表}
    {初始化列表,}
…</pre>
  
  

…</p>

12 本小节的其余部分处理具有聚合或联合类型的对象的初始值设定项。

…</p>

16 否则,具有聚合或联合类型的对象的初始化程序应为元素或命名成员的初始化程序的大括号括起来的列表

6.7.8:16 中的重点是我的。基本上,这是您的程序不满足的 C99 标准的一部分。

于 2015-01-01T20:55:46.020 回答
-1

Compound literal has different behavior in C99 and C++.

In C++ it has only a single expression storage duration, not automatic duration. If this is compiled in C++ mode, then it won't work, because the compound literal object disappears after the expression finishes.

This might explain @cremno's description on static vs automatic storage duration.

于 2015-01-02T05:13:13.143 回答