C99标准要求用于定义枚举常量值的表达式具有可表示为int
的值。
在第6.7.2.2节 C99标准第2段中:
定义枚举常量值的表达式应为整数 具有可表示为
int
的值的常量表达式。
但是,实现可以定义枚举类型以与任何整数类型兼容,包括范围超出int
的值。
在第6.7.2.2节 C99标准第2段中:
每个枚举类型应与
char
,有符号整数类型或 无符号整数类型。
这意味着虽然您无法在int
范围之外显式设置枚举常量的值,但如果实现定义,则枚举常量的值可能超出int
的范围枚举类型与范围超出int
的整数类型兼容。
现在我知道一种获取枚举常量int
范围之外的特定值的方法:虚拟枚举器。
enum hack{
DUMMY0 = INT_MAX,
DUMMY1,
/* supply as many more dummy enumerators as needed */
...
/* declare desired enumerator */
FOOBAR
};
这要归功于C99标准的第6.7.2.2节第3段:
=
的枚举器定义了它 枚举常量作为常量表达式的值 ...
没有=
的每个后续枚举数 将其枚举常量定义为由其获得的常量表达式的值 将1加上前一个枚举常量的值。
不幸的是,这仅适用于大于INT_MAX
的正值,因为每个后续枚举器的值只会递增。另一个需要注意的是,需要创建可能的许多虚拟枚举器才能获得所需的特定枚举器。
这导致以下问题:
int
范围之外的负值?int
范围之外的枚举常量?enum
中声明的枚举数设置了限制?答案 0 :(得分:10)
如何设置枚举常量的值超出int范围?
你没有。
C99标准要求用于定义值的表达式 枚举常量的值具有可表示为
int
的值。
是的,C11标准没有改变任何一个。
但是,枚举类型可以由实现定义 兼容任何整数类型,包括范围为 值
int
以外的值。
也正确。
这意味着虽然您无法明确设置值 枚举常量超出
int
范围,a的值 枚举常量可以在int
的范围之外 实现定义了与a兼容的枚举类型 范围超出int
的整数类型。
这是不正确的,但我认为你发现标准中的措辞存在缺陷。 (更新:我认为这不是一个弱点;见下文)。你引用了6.7.2.2:
定义枚举常量值的表达式 是一个整数常量表达式,具有可表示为的值 的 INT 强>
似乎仅在值由显式表达式定义时才适用,而不是像这样的情况:
enum too_big {
big = INT_MAX,
even_bigger
};
但这实际上并不起作用,因为even_bigger
被声明为int
类型的常量,显然不能具有值INT_MAX + 1
。
我强烈怀疑意图是上述声明是非法的(违反约束);应该重新编写6.7.2.2以使其更清晰。 (更新:我现在认为它已经足够清楚了;见下文。)
gcc的作者似乎同意我的观点:
$ cat c.c
#include <limits.h>
enum huge {
big = INT_MAX,
even_bigger
};
$ gcc -c c.c
c.c:4:5: error: overflow in enumeration values
因此,即使您的解释是正确的,您也不太可能编写和使用依赖于它的代码。
解决方法是使用整数(无论如何,枚举类型或多或少都是伪装的整数)。遗憾的是,const
整数对象不是常量表达式,因此您可能不得不求助于使用预处理器:
typedef long long huge_t;
#define big ((huge_t)INT_MAX)
#define even_bigger (big + 1)
这假定long long
宽于int
,这可能但不能保证(如果int
是long long
,则int
和int
的大小可能相同至少64位)。
你的问题1和2的答案是否定的;你不能在INT_MIN
范围之外定义枚举常量,为负数或正数。
至于你的问题3,C11标准的第5.2.4.1节(大致)说,编译器必须在单个枚举中支持至少 1023个枚举常量。大多数编译器实际上并没有强加固定限制,但在任何情况下,所有常量都必须具有INT_MAX
... enum too_big {
big = INT_MAX,
even_bigger
};
范围内的值,因此这对您没有多大帮助。 (同一类型中的多个枚举常量可以具有相同的值。)
(翻译限制要求实际上比这更复杂。编译器必须支持至少一个程序,该程序至少包含一个枚举列表的所有实例。这是一个相当无用的要求如上所述。目的是满足标准要求的最简单方法是避免施加任何固定限制。)
更新:
我在comp.std.c Usenet新闻组中提出了这个问题。 Tim Rentsch在讨论中提出了一个很好的观点,我现在认为:
int
是违反约束的,需要编译器诊断。
我担心的是禁止显式值超出int
范围的措辞:
定义枚举常量值的表达式 是一个整数常量表达式,具有可表示为的值 的 INT 强>
不适用,因为没有涉及(显式)表达式。但6.7.7.2p3说:
没有 = 的每个后续枚举器定义其枚举 常量为通过加1获得的常量表达式的值 到前一个枚举常量的值。
(重点补充)。所以有一个表达式,其值必须可以表示为{{1}};它只是没有出现在源代码中。我对此并不十分满意,但我认为其意图非常明确。
这是comp.std.c上的discussion。
答案 1 :(得分:3)
也许我不能说Keith Thompson没有告诉你的任何事情 无论如何,我会尝试。
<强> 1。 int
范围内的值在 ISO C99 的文件中,我可以在 6.7.2.2 ,第2和第3段中看到以下陈述:
(2)定义枚举常量值的表达式应为整数 具有可表示为int的值的常量表达式。
如果您写enum T { X = (expr) } VAR
,则expr
是 int 范围内的整数,其中至少包括范围 -32767。 。+ 32767 ,正如您在5.2.4.2.1
中所读到的那样
当然,段落(2)不会对标识符 X 的类型施加任何限制。
<强> 2。枚举器标识符的类型为int
在 3 段中,我们可以读到这一行:
(3a)枚举器列表中的标识符被声明为具有int类型的常量,并且可以出现在允许的地方。
这是对标识符类型的限制。现在 X 的类型为 int 。
第3。关于价值观的讨论
此外,标准说:
(3b)枚举数=将其枚举常量定义为常量表达式的值。
但是这句话现在受到(2)和(3a)的限制。
所以,我对标准C99的解释如下:
如果你写
enum T { X = INT_MAX, BIGG}
然后BIGG
的类型为 int (根据(3a))。
正如Keith Tompson指出的那样, BIGG 的值(= &#34;枚举常量?&#34; )不是来自表达式,表示超出范围的值(对于 int )。它的值(在数学意义上)是 X + 1 ,因为应用了下一个规则:
(3c)每个后续的枚举器没有= 将其枚举常量定义为得到的常量表达式的值 将1添加到上一个枚举常量的值。
在这种情况下,标准(关于整数算术)中没有定义编译器行为的规则。所以,它会落在implementation defined
级......中
但是,如果编译器接受此超出范围的值,我相信(数学) X + 1 将转换为 int 中的值范围。
但是,(3b)中的预期行为似乎是 C 表达(X + 1)== BIGG 总是的真即可。 如果我是对的,那么我同意Keith,并且编译器必须拒绝声明超出范围错误。
<强> 4。枚举类型的整数类型
我们可以阅读更多内容:
(4a)每个枚举类型应与char,有符号整数类型或者 无符号整数类型。
声明enum T
定义了一个新的整数类型
此类型与表达式 expr
的类型无关,
既不是枚举器的类型 X
它只是另一种类型:与我们定义的枚举类型T
相关联的整数类型。
(此类型将分配给变量VAR_T
)。
实现可以决定哪种整数类型更合适
如果表达式(如expr
)的值非常小,几乎总是如此,
然后编译器可以决定T
的类型为 char ,例如
如果由于某种原因需要很长,
那么T
的类型将长很长,依此类推。
但是,这不会更改 int 的限制,表达式expr
和枚举器X
必须遵循。它们是 int 。
与expr
和T
类型相关的唯一规则是:
(4b)类型的选择是实现定义的,但应能够表示枚举的所有成员的值。
因此,如果您有enum T { X = 0, Y = 5, Z = 9 }
,则T
的类型可以是字符。
(这种情况类似于一个字符常量,如'c'
,总是将类型 int 传递给 char 变量:{{1虽然char c = 'c';
是 int ,但其值适合 char 的范围。
另一方面,如果您有'c'
,则编译器无法为enum T { X = 20202, Y = -3 }
选择 char 。似乎 int 是T
的完美类型(对于任何 enum 类型),但编译器可以为{{1}选择任何其他整数类型其范围包含值 20202 和 -3 。
如果没有值为负,则编译器可以选择T
整数类型。
<强> 5。摘要
总之,我们可以这样说:
T
),值(或枚举常量,来自表达式或仅隐式),枚举器(unsigned
)和枚举类型(expr
)。 X
)始终为 int 。值的类型似乎不在 int 的范围内(T
似乎是不允许的)。枚举器的类型是 int (如expr
)。并且枚举类型(如INT_MAX+1
)由实现选择,在允许的所有可能的整数类型中,只是在声明中拟合值。 在表达式中,我们有:
X
T
表达式#define NN 5
是 int 。
表达式enum T { X = 0. Y = 3, Z = (NN*3) } evar;
是 int
如果编译器将(NN * 3) + 1
定义为 char ,则
然后表达式(Z + 1)
是 char 。
答案 2 :(得分:1)
回应最近Keith Thompson的更新:
我认为你是对的:标准说...the value of the constant expression obtained by adding 1 to the value...
因此,非显式表达“值”也被视为来自常量表达式。
但是,为了确保只允许 int “值”,必须共同考虑第2段声明的限制:The expression that defines the value of an enumeration constant ... has a value representable as an int
。
因此,(非显式表达式)值也必须适合 int 。
我现在确信,预期的约束是每个枚举器值都适合 int 。
谢谢你,基思。