C中枚举器列表中枚举常量的类型

type of enumeration constants inside enumerator list in C

已编辑

我目前正在开发一个多平台枚举解析器,在尝试回答上述问题时发现了这种奇怪的行为。

问题A)

C标准是否在枚举声明完成之前确定枚举常量的类型?

以Keil ARMCC为例:

enum e {
    VAL0 = (signed char)126,
    VAL1,
    VAL2, 
    SIZE0 = sizeof(VAL0), 
    SIZE1 = sizeof(VAL1), 
    SIZE2 = sizeof(VAL2) 
};

我得到 SIZE0 = 1,SIZE1 = 1,SIZE2 = 8。 (如果我评估定义之外的枚举常量的大小,所有的大小都是 int)。

他们不应该都等于 sizeof( int ) 吗? (请记住,在本例中,int 的大小为 4 个字节。)

问题B)

对于Keil C251,我有以下内容:

signed int VALUE0 = (signed char)-1;
enum{ VALUE1 = (signed char)-1 };
enum{ VALUE2 = -1 };
printf( "Is VALUE0 equal to VALUE1? ---> %s", VALUE0 == VALUE1 ? "Yes!" : "No!" );
printf( "Is VALUE0 equal to VALUE2? ---> %s", VALUE0 == VALUE2 ? "Yes!" : "No!" );

打印:

Is VALUE0 equal to VALUE1? ---> No!
Is VALUE0 equal to VALUE2? ---> Yes!

不应该都打印 yes 吗?

我遗漏的 VALUE0 和 VALUE1 的定义之间是否存在差异,也许是类型转换?或者这可能是编译器错误?

在 C 中(与 C++ 不同),枚举常量的类型为 int。在类型声明结束之前引用枚举常量是合法的。

如果 Keil ARMCC 给你 sizeof(VAL0) != sizeof (int),其中 VAL0 是一个枚举常量,那么 Keil ARMCC 就不是一个符合规范的 C 编译器。我在这里看到其他问题表明它不符合要求。

不符合规范不一定是编译器错误(除非供应商声称它符合规范,但据我所知他们没有)。

关于 B 部分:

enum e{
    MIN_SIGNED_CHAR_0 = (signed char)( -128 ),
    MIN_SIGNED_CHAR_1 = -128,
    MIN_SIGNED_CHAR_2 = (  signed int)(signed char)( -128 ),
    MIN_SIGNED_CHAR_3 = (unsigned int)(signed char)( -128 ),
    MIN_SIGNED_CHAR_0_PLUS_1 = MIN_SIGNED_CHAR_0 + 1,
    MIN_SIGNED_CHAR_1_PLUS_1 = MIN_SIGNED_CHAR_1 + 1,
    MIN_SIGNED_CHAR_2_PLUS_1 = MIN_SIGNED_CHAR_2 + 1,
    MIN_SIGNED_CHAR_3_PLUS_1 = MIN_SIGNED_CHAR_3 + 1,
};

几乎所有符合规范的 C 编译器都应该为 MIN_SIGNED_CHAR_{0,1,2} 常量提供值 -128int 类型),为 MIN_SIGNED_CHAR_{0,1,2}_PLUS_1 常量提供值 -127(也是 int 类型)。唯一可能的摆动空间是使用 SCHAR_MIN == -127 的实现,这是可能的但不太可能,并且显然 而不是 Keil 编译器的情况。如果您得到不同的结果,要么是编译器中的错误。

但是MIN_SIGNED_CHAR_3的定义是有问题的。 int-128 转换为 signed char,这不会更改值。然后将其转换为 unsigned int,得到 UINT_MAX+1-128(假设 32 位,这是 4294967168)。指定值超出 int 范围的枚举常量是违反约束的,需要进行诊断。 (你收到编译时警告了吗?)如果编译器不拒绝该程序,结果是未定义的。