为什么 GCC 不能在结构初始值设定项中以 sizeof 作为条件的三元中处理复合文本的编译时计算?

Why can GCC not handle compile-time evaluation of compound literal in a ternary with sizeof as a condition inside a struct initializer?

提问人:user16217248 提问时间:10/16/2023 更新时间:10/16/2023 访问量:104

问:

以下代码:

struct Int {
    int i;
};
const struct Int i = {sizeof(int) ? (int){1} : 0};

结果:

initializer 元素不是常量

(现场演示 GCC)

即使这些语句在文件范围内,因此复合文本也应被视为常量。

但是,如果:

  • 我改用 Clang;或
  • 我用 0 替换 ;或sizeof(int)
  • 我用 1 替换 ;或(int){1}
  • 表达式用于直接初始化结构成员,而不是结构成员,如下所示:intintint i = sizeof(int) ? (int){1} : 0;

代码可以很好地编译。

这引发了几个问题:

  • 标准 C 是否允许使用与三元一起使用的语句将一个全局结构变量成员初始化为 2 个值之一,其中至少一个是复合文本,所有这些都在编译时完成?sizeof()
  • 如果满足上述所有 3 个要求,为什么 GCC 会引发错误,但如果只满足任何 2 或 1 个,代码就可以正常编译?
C GCC 条件运算符 编译时 复合文字

评论

0赞 Erich Kitzmueller 10/16/2023
(int){1}对我来说看起来很奇怪,但是,C有一些奇怪的怪癖。
0赞 Some programmer dude 10/16/2023
与你一起告诉编译器将值视为值。这毫无意义。我想只是为了这个问题,你才有那个复合字面意思?因为如果它在某个地方的真实代码中,那么只需将其删除即可。如果这只是出于好奇,那很好,但请在问题本身中说明。否则,请直接询问根本问题。(int){1}int1int
0赞 Some programmer dude 10/16/2023
@user16217248I知道,以为这是先标记C++,所以当我看到它不是时删除了原始评论。
0赞 ikegami 10/16/2023
@Some程序员伙计,不过,不正确的评论仍然存在。 不是演员。它不会告诉编译器将该值视为 .总的来说,这确实是有道理的(尽管不是这里如何使用它)。(int){1}int1int(int){1}
1赞 user16217248 10/16/2023
@Someprogrammerdude 这是一个“最小的可重复示例”。实际上,我会使用复合文字来表示结构或其他东西。

答:

1赞 Lundin 10/16/2023 #1

在 C23 之前,关于整数常量表达式的组成,在 gcc 和 clang 错误报告等中有很多争论。Clang总是有“任何事物及其母亲都是恒定的表达”的行为,而GCC则更加严格,直到后来的版本,GCC突然翻转了行为,尽管这里的标准已经很久没有改变过了。所有这些都是由 C17(和早期标准)6.6 §10 中一个无益的、浑浊的段落引起的:

实现可以接受其他形式的常量表达式。

这是第 6.6 章中唯一留有解释空间并允许像您这样的代码的部分。这意味着整数常量表达式在 gcc 和 clang 中都有不稳定的支持,代码使用常量表达式的“异国情调”形式,例如复合文字,或者根本不是不可移植的。市场上的大多数其他编译器都会给出有关不合格 C 的诊断信息。const int x = some_other_const;


在 C17 之前,整数常量表达式定义如下 (C17 6.6 §6):

整数常量表达式应具有整数类型,并且只能具有整数常量、枚举常量、字符常量、结果为整数的表达式的操作数 常量、表达式和浮动常量,它们是强制转换的直接操作数。sizeof_Alignof

在即将到来的 C23 中,此更改(C23 N3096 草案 6.6. §8 强调我的):

整数常量表达式应具有整数类型,并且只能具有作为整数常量的操作数、整数类型的命名和复合文字常量、字符常量、...

其中“命名常量”是一个新术语,除其他外,它涵盖了以下内容:

使用 storage-class 说明符声明,并具有对象类型,constexpr

因此,C23 将允许复合文字,我们也可以便携式地这样做(constexpr int){1}constexpr int x = 1; const int y=x;

评论

0赞 user16217248 10/16/2023
它明确地将整数常量表达式定义为这些东西的列表,直到后来他们才忘记了复合文字。但是,非整数类型呢?struct
0赞 Lundin 10/16/2023
@user16217248 “但是结构体或非整数类型呢?”与此问题无关,请单独提问。
0赞 user16217248 10/17/2023
虽然这个问题是在我使用结构体时出现的,但我以整数为例提出了这个问题,因为我的印象是,无论我使用整数还是结构体,答案都不会有任何不同。显然不是,因为 C 标准明确定义了整数常量表达式,而不仅仅是常量表达式,而不管类型如何。
0赞 Lundin 10/17/2023
@user16217248 常量表达式有多种形式,在初始化过程中规则稍微宽松一些 - 允许使用各种其他形式的常量作为初始值设定项,但其他结构不允许。同样,这个话题太复杂了,无法在评论中讨论。