【问题标题】:type of enumeration constants inside enumerator list in CC中枚举器列表内的枚举常量类型
【发布时间】:2016-08-15 08:50:37
【问题描述】:

已编辑

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

问题 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 的定义是否有区别,也许是类型转换?或者这可能是一个编译器错误?

【问题讨论】:

  • 这是enums 在 C 中对嵌入式系统不是很有用的主要原因:port70.net/~nsz/c/c11/n1570.html#6.4.4.3p2 请注意,C 不仅有规范,还有标准(ISO9899,当前版本是 2011 ,又名 C11)。常见的建议是使用类似常量的宏。请注意,const 限定变量仍然不是 常量,但是 - 嗯 - C 中的变量。因此您的变量非常无用。
  • 这就是我的意思。我从规范变为标准。
  • 请注意,enum 的大小是实现定义的,因此受 PCS/ABI 的约束。对于 ARM,请参阅 AAPCS。
  • 可以,但不是枚举常量的大小。
  • 在枚举数列表之外,sizeof(VAL0) = sizeof(VAL1) = sizeof(VAL2) = sizeof(int)。我的问题是关于枚举器列表中的大小和类型,在枚举声明完成之前。

标签: c enums embedded keil


【解决方案1】:

在 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} 常量提供值 -128(int 类型),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 范围的指定值的枚举常量是违反约束的,需要进行诊断。 (您是否收到编译时警告?)如果编译器不拒绝程序,结果是未定义的。

【讨论】:

  • enum 定义完成后编译器会生成正确的大小,我强烈怀疑存在故障。由于在定义期间使用 sizeof 一个 enum-constant 是非常无用的,因此他们可能没有进行测试(从编译器构造视图来看,这仍然是一种奇怪的行为)。无论如何,我认为OP更关心其他编译器。
  • 太好了,凯尔!对问题 B 有任何想法吗?
  • @saoPaulo:是的,unsigned int 演员阵容是个问题。请参阅我的更新答案。
  • @Thompson:嗯,实际上我更关心 MIN_SIGNED_CHAR_0 的值与 MIN_SIGNED_CHAR_2 和 c 不同。据我了解, signed int VALUE0 = (signed char)-1 和 enum{ VALUE1 = (signed char)-1 } 之间的值应该没有区别。如果 VALUE0 != VALUE1,我可以确认这是一个错误吗?
  • 严格来说,由于MIN_SIGNED_CHAR_3的定义无效(违反约束),整个程序的行为是不确定的。如果您删除它并且仍然获得MIN_SIGNED_CHAR_0 与MIN_SIGNED_CHAR_2 的不同值,那么是的,我会说这是一个错误 - 或者至少是不合格的。但是,如果编译器将枚举常量设为int 以外的其他类型,则可能是可以预期的。一个更简单的例子,也许只有两个枚举常量(而且名称比a、b、c 等更容易混淆)会有所帮助。
猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-21
  • 2013-03-13
  • 2011-07-09
  • 2012-09-16
相关资源
最近更新 更多