【问题标题】:Can I treat an `enum` variable as an `int` in C17?我可以在 C17 中将“枚举”变量视为“int”吗?
【发布时间】:2021-06-11 04:59:06
【问题描述】:

TL;DR:假设enum NAME {...}; 在执行期间enum NAME nint n 相同,是否正确? n 是否可以像 signed int 一样被操作,即使它被声明为 enum NAME?原因:我真的很想使用enum 类型作为返回标志,作为关于位操作的“关闭”类型。

例如:让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 在分配一个不是成员的值时的行为方式是依赖于实现。我询问的部分原因是为了确认或否认这一说法。

【问题讨论】:

    标签: c types enums standards c17


    【解决方案1】:

    这在您链接的 PDF 的第 6.4.4.3 章中:

    声明为枚举常量的标识符的类型为int

    您认为将enum NAME x 提升为signed int x 的想法并不正确,因为它是int 类型的标识符 NAME x 是您用来定义标识符的类型,它被提升为int

    此外,整数提升发生在整数运算中。

    编辑

    一些编译器非常重视enumint 之间的区别,特别是如果他们可以选择将位宽减小到尽可能小。例如,我在工作项目中使用的那个会自动插入检查 每个 使用 enum 值对定义的值。此外,IIRC,它拒绝所有隐式转换,我们需要显式转换:

    FLAGS f = (FLAGS)((int)F1 | (int)F2);
    

    但这是这种特殊野兽的扩展,具有特定的安全选项......

    【讨论】:

      【解决方案2】:

      C 2018 6.7.2.2 4 说:

      每个枚举类型都应与char、有符号整数类型或无符号整数类型兼容。类型的选择是实现定义的,但应该能够表示枚举所有成员的值……

      所以“我可以在 C17 中将 enum 变量视为 int 吗?”的答案?不是,因为枚举类型的对象实际上可能是char 或其他不同于int 的整数类型。

      然而,它实际上是一个整数类型,所以FLAGS f = F1 | F2; 可以工作:FLAGS 类型必须能够表示其值F1F2,所以用于FLAGS 的任何类型都必须包含F1F2的所有位,所以它包含F1 | F2的所有位。

      从技术上讲,您可以通过操作位来构造陷阱表示,因此不能保证在位操作下该类型是关闭的。例如,如果 C 实现对 32 位 int 使用二进制补码,但保留位模式 1000…0000 作为陷阱表示,则 INT_MIN & -2 将是陷阱表示。 (INT_MIN 将具有位模式 1000…0001,对于 231-1,而-2 将具有模式 1111…1110。)在没有陷阱表示的 C 实现中不会发生这种情况它的整数类型。

      我们可能会质疑两种类型(枚举及其实现定义的整数类型)是否兼容这一事实是否意味着我们可以将一种用作另一种。如果两种类型相同(6.2.7 1),则它们是兼容的,并且唯一可以使类型兼容但不相同的事物涉及限定符(例如const),这不是问题或涉及其他属性(例如作为数组维度)与简单整数类型无关。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多