【问题标题】:clang enum overflow铿锵枚举溢出
【发布时间】:2013-03-08 21:27:11
【问题描述】:

使用 -Wall -pedantic

#include <limits.h>
#include <stdio.h>

int main(void)
{
    enum x {
        a,
        max = INT_MAX,
        out_1
    };
    enum y {
        b,
        out_2 = INT_MAX + 1
    };


    printf("%d %d\n", out_1, out_2);
    return 0;
}

叮当声返回

demo.c:9:3: warning: overflow in enumeration value
                out_1
                ^

如你所见,编译器并没有警告out_2溢出,他的值在编译时是未知的?

【问题讨论】:

  • 相当肯定标准没有定义enum的范围。
  • 我的猜测:它首先评估 INT_MAX+1,它会环绕并将其分配给 out_2。
  • @johnny:不,它调用了 UB。

标签: c enums overflow


【解决方案1】:

首先,编译器本身试图选择一个导致溢出的整数,因此会警告您。它很可能产生INT_MIN。该标准允许signed int 中的任何值成为枚举常量(见底部)。

在第二个中,表达式(INT_MAX + 1) 在分配给out_2 之前计算。此处表达式中的溢出会产生允许的结果,但这是未定义的行为。然后将有效结果存储在枚举中,这就是不产生第一个错误的原因。

clang (3.2) 也不会对此发出警告,这实际上是相同的:

int a = INT_MAX + 1;

在这方面,clang 的行为不符合 C 标准,因为这是未定义的。

对比 gcc 的输出,区别就很明显了:

In function ‘main’:
9:9: error: overflow in enumeration values
13:25: warning: integer overflow in expression [-Woverflow]

英特尔编译器忽略枚举溢出,但警告整数溢出:

enum.c(13): warning #61: integer operation result is out of range
      out_2 = INT_MAX + 1
                      ^


作为参考,来自 C99 标准 6.7.7.2.2,“定义枚举常量值的表达式应为整数常量表达式,其值可表示为 int;.3,”枚举器中的标识符list 被声明为具有int 类型的常量,并且可以出现在任何允许的地方。”即枚举常量可以是任何int 值,并且具有int 类型。定义的枚举变量的结果类型可以是charintunsigned int,只要它允许枚举中的所有可能常量。因此,示例中的 enums 都未定义,因为它们都需要整数溢出。第一个是明确的非法的。

【讨论】:

  • 但问题是:为什么 Clang 会警告 out_2。
  • @eznme:第二点——在这种情况下,计算表达式后整数是一个有效的枚举。
  • @eznme 我猜这是因为-Wall 用词不当。使用-Weverything,甚至可能是-Wextra,我希望clang 会警告溢出。
  • @DanielFischer:没有任何使用 clang 3.2 的警告。 gcc 警告没有任何 -W 选项。
  • @eznme 有符号整数溢出完全未定义。
【解决方案2】:

ISO C 将整数指定为枚举值。

如果您的编译器允许(GCC 和 Clang 允许),那么 INT_MIN 是一个非常好的值。

如果编译器不允许指定索引,则需要发出错误

显式请求的 INT_MIN 没问题但 INT_MAX 前身的自动增加值发出 警告 的原因是,该标准需要 +1 行为。

【讨论】:

  • enum 常量是int
  • @ouah 是的,正如我所说。 (我用的第四个词)
  • 所以你承认 enum 常量 INT_MIN 必须被所有 C 编译器接受?
  • @ouah:每个正方形都是矩形,但不是每个矩形都是正方形。每个枚举常量都可以表示为一个整数,但并非每个整数都必须可以作为枚举常量接受。
  • @eznme:“至少需要 0...1023”的说法不正确。任何int 都可以是枚举值。仔细阅读您刚刚引用的链接,它并没有说明您声称的内容。
猜你喜欢
  • 2013-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
  • 2016-10-24
  • 1970-01-01
相关资源
最近更新 更多