我可以在 C17 中将 `enum` 变量视为 `int` 吗?
Can I treat an `enum` variable as an `int` in C17?
TL;DR:假设 enum NAME {...};
在执行期间 enum NAME n
与 int n
相同是否正确? n
是否可以像 signed int
一样操作,即使它被声明为 enum NAME
?原因:我真的想对 return 标志使用 enum
类型,作为 'closed' 相对于位操作的类型。
例如:设typedef enum FLAGS { F1 = 0x00000001, F2 = 0x00000002, F3 = 0x00000004 } FLAGS ;
然后,FLAGS f = F1 | F2;
将 3
分配给 f
,不抛出相关错误或警告。这个和许多其他编译器允许的使用场景,例如 f++
,让我觉得我可以合法地将 f
当作 signed int
。使用的编译器:MSVC'19、16.9.1,设置为“C17 (2018) Standard (/std:c17)”;
我搜索了标准(草图 here)并查看了其他相关问题,但没有提及怀疑(并希望)成为 enum NAME x
的“无声提升” signed int x
,即使标识符具有该类型。这让我相信 enum
在分配一个非成员的值时的行为方式 依赖于实现 。我问,部分是为了确认或否认这一说法。
这在您链接的 PDF 的第 6.4.4.3 章中:
An identifier declared as an enumeration constant has type int
.
您关于将 enum NAME x
提升为 signed int x
的想法是不正确的,因为它是 identifier NAME
输入 int
。 value x
是你用来定义标识符的类型,它被提升为 int
.
此外,整数提升发生在整数运算中。
编辑
一些编译器非常重视 enum
和 int
之间的区别,尤其是当它们可以选择将位宽减小到尽可能小的时候。例如,我在工作项目中使用的那个,会根据定义的值自动插入检查 each 对 enum
值的使用情况。此外,IIRC,它拒绝所有隐式转换,我们需要显式转换,类似于:
FLAGS f = (FLAGS)((int)F1 | (int)F2);
但这是这种特殊的野兽的扩展,具有特定的安全选项...
C 2018 6.7.2.2 4 说:
Each enumerated type shall be compatible with char
, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration…
“我可以在 C17 中将 enum
变量视为 int
吗?”的答案不是,因为具有枚举类型的对象实际上可能是 char
或不同于 int
.
的其他整数类型
然而,它实际上是一个整数类型,所以 FLAGS f = F1 | F2;
可以工作: FLAGS
类型必须能够表示它的值 F1
和 F2
,所以用于 FLAGS
的任何类型都必须包含 F1
和 F2
的所有位,因此它包含 F1 | F2
.
的所有位
从技术上讲,您可以通过操作位来构造陷阱表示,因此不能保证类型在位操作下是封闭的。例如,如果 C 实现对 32 位 int
使用二进制补码,但保留位模式 1000…0000
作为陷阱表示,则 INT_MIN & -2
将是陷阱表示。 (对于 231−1,INT_MIN
将具有位模式 1000…0001
,而 -2
将具有模式 1111…1110
。)在其整数类型中没有陷阱表示的 C 实现中不会发生这种情况。
我们可能会质疑两种类型(枚举及其实现定义的整数类型)兼容的事实是否意味着我们可以将一种用作另一种。如果两种类型相同(6.2.7 1),则它们是兼容的,并且唯一可以使类型兼容但不相同的东西涉及限定符(如 const
),这不是问题或涉及其他属性与简单整数类型无关的(例如数组维度)。
TL;DR:假设 enum NAME {...};
在执行期间 enum NAME n
与 int n
相同是否正确? n
是否可以像 signed int
一样操作,即使它被声明为 enum NAME
?原因:我真的想对 return 标志使用 enum
类型,作为 'closed' 相对于位操作的类型。
例如:设typedef enum FLAGS { F1 = 0x00000001, F2 = 0x00000002, F3 = 0x00000004 } FLAGS ;
然后,FLAGS f = F1 | F2;
将 3
分配给 f
,不抛出相关错误或警告。这个和许多其他编译器允许的使用场景,例如 f++
,让我觉得我可以合法地将 f
当作 signed int
。使用的编译器:MSVC'19、16.9.1,设置为“C17 (2018) Standard (/std:c17)”;
我搜索了标准(草图 here)并查看了其他相关问题,但没有提及怀疑(并希望)成为 enum NAME x
的“无声提升” signed int x
,即使标识符具有该类型。这让我相信 enum
在分配一个非成员的值时的行为方式 依赖于实现 。我问,部分是为了确认或否认这一说法。
这在您链接的 PDF 的第 6.4.4.3 章中:
An identifier declared as an enumeration constant has type
int
.
您关于将 enum NAME x
提升为 signed int x
的想法是不正确的,因为它是 identifier NAME
输入 int
。 value x
是你用来定义标识符的类型,它被提升为 int
.
此外,整数提升发生在整数运算中。
编辑
一些编译器非常重视 enum
和 int
之间的区别,尤其是当它们可以选择将位宽减小到尽可能小的时候。例如,我在工作项目中使用的那个,会根据定义的值自动插入检查 each 对 enum
值的使用情况。此外,IIRC,它拒绝所有隐式转换,我们需要显式转换,类似于:
FLAGS f = (FLAGS)((int)F1 | (int)F2);
但这是这种特殊的野兽的扩展,具有特定的安全选项...
C 2018 6.7.2.2 4 说:
Each enumerated type shall be compatible with
char
, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration…
“我可以在 C17 中将 enum
变量视为 int
吗?”的答案不是,因为具有枚举类型的对象实际上可能是 char
或不同于 int
.
然而,它实际上是一个整数类型,所以 FLAGS f = F1 | F2;
可以工作: FLAGS
类型必须能够表示它的值 F1
和 F2
,所以用于 FLAGS
的任何类型都必须包含 F1
和 F2
的所有位,因此它包含 F1 | F2
.
从技术上讲,您可以通过操作位来构造陷阱表示,因此不能保证类型在位操作下是封闭的。例如,如果 C 实现对 32 位 int
使用二进制补码,但保留位模式 1000…0000
作为陷阱表示,则 INT_MIN & -2
将是陷阱表示。 (对于 231−1,INT_MIN
将具有位模式 1000…0001
,而 -2
将具有模式 1111…1110
。)在其整数类型中没有陷阱表示的 C 实现中不会发生这种情况。
我们可能会质疑两种类型(枚举及其实现定义的整数类型)兼容的事实是否意味着我们可以将一种用作另一种。如果两种类型相同(6.2.7 1),则它们是兼容的,并且唯一可以使类型兼容但不相同的东西涉及限定符(如 const
),这不是问题或涉及其他属性与简单整数类型无关的(例如数组维度)。