9

C 定义了至少 3 个级别的“常量表达式”:

  • 常量表达式(不合格)
  • 算术常数表达式
  • 整数常量表达式

6.6 第 3 段内容如下:

常量表达式不应包含赋值、递增、递减、函数调用或逗号运算符,除非它们包含在未计算的子表达式中。

那么这是否意味着1,2不是一个常量表达式?

第 8 段内容如下:

算术常量表达式应具有算术类型,并且只能具有整数常量、浮动常量、枚举常量、字符常量和 sizeof 表达式的操作数。算术常量表达式中的强制转换运算符只能将算术类型转换为算术类型,但作为结果为整数常量的 sizeof 运算符的操作数的一部分除外。

中的操作数是(union { uint32_t i; float f; }){ 1 }.f什么?如果1是操作数,那么这可能是一个算术常量表达式,但如果{ 1 }是操作数,那么显然不是。

编辑:另一个有趣的观察:7.17 第 3 段要求结果是offsetoftype 的整数常量表达式size_t,但offsetof据我所知,标准的实现不需要是标准的整数常量表达式。这当然没问题,因为允许实现(根据 6.6 第 10 段)接受其他形式的常量表达式,或者实现offsetof__builtin_offsetof而不是通过指针减法。然而,这个观察的本质是,如果你想offsetof在需要整数常量表达式的上下文中使用,你真的需要使用实现提供的宏,而不是自己滚动。

4

2 回答 2

2

根据你的阅读,1,2不是一个恒定的表达。我不知道为什么不是,只是我同意你的观点,它不是(尽管它可能应该是)。

6.5.2 将复合文字指定为后缀运算符。所以在

(union { uint32_t i; float f; }){ 1 }.f

操作数是(union { uint32_t i; float f; }){ 1 }f.运算符。它不是算术常量表达式,因为第一个参数是一个union类型,但它是一个常量表达式。

更新:我是基于对标准的不同解释。

我之前的推理是(union { uint32_t i; float f; }){ 1 }.f符合常量表达式的标准,因此是常量表达式。我仍然认为它符合常量表达式的标准(6.6 第 3 段),但它不是常量表达式的任何标准类型(整数、算术或地址),因此只能成为 6.6 段的常量表达式10,它允许实现定义的常量表达式。

我也一直想进行您的编辑。我要争辩说“hack”的实现offsetof是一个常量表达式,但我认为它与上面相同:它符合常量表达式(可能是地址常量)的标准,但不是整数常量表达式,并且因此在 6.6 第 10 段之外无效。

于 2011-02-04T00:48:07.213 回答
1

如果1,2将是一个常量表达式,这将允许这样的代码编译:

{ // code        // How the compiler interprets:
  int a[10, 10]; // int a[10];

  a[5, 8] = 42;  // a[8] = 42;
}

我不知道这是否是真正的原因,但我可以想象为这个(常见的?)错误发出错误被认为比1,2变成一个常量表达式更重要。

更新:正如 R. 在评论中指出的那样,自从引入 VLA 以来,关于的代码不再是编译器错误。

于 2011-02-04T05:58:49.920 回答