是否允许枚举具有未列出的值?[duplicate]

brjng4g3  于 2022-12-29  发布在  其他
关注(0)|答案(6)|浏览(182)

此问题在此处已有答案

What happens if you static_cast invalid value to enum class?(1个答案)
七年前就关门了。
说,我们有

enum E
{
  Foo = 0,
  Bar = 1
};

现在我们知道了

enum E v = ( enum E ) 2;

然后

switch ( v )
{
  case Foo:
    doFoo();
  break;
  case Bar:
    doBar();
  break;
  default:
    // Is the compiler required to honor this?
    doOther();
  break;
}

由于上面的开关处理枚举的每个可能列出的值,是否允许编译器优化掉上面的default分支,或者在枚举的值不在列表中的情况下具有未指定或未定义的行为?
因为我期望C和C的行为应该是相似的,所以问题是关于这两种语言的。然而,如果C和C在这种情况下有区别,那么知道它也是很好的。

rekjcdws

rekjcdws1#

C++情况

在C++中,每个枚举都有一个基础整型。如果显式指定,它可以是 * fixed *(例如:enum test2 : long { a,b};),或者在scoped枚举的情况下默认为int(例如:enum class test { a,b };):

  • *[dcl. enum ]/5:**每个枚举定义一个与所有其他类型不同的类型。每个枚举还具有一个 * 基础类型 *。(...)如果未显式指定,则作用域枚举类型的基础类型为int。在这些情况下,基础类型被称为固定类型。

unscoped枚举的情况下,底层类型没有显式地固定(您的示例),该标准为您的编译器提供了更大的灵活性:

  • *[dcl. enum ]/7:**对于基础类型不固定的枚举,基础类型是可以表示枚举中定义的所有枚举数值的整型。(...)由实现定义将哪种整型用作基础类型,除非枚举数的值无法放入int或unsigned int,否则基础类型不应大于int。

现在有一个非常棘手的问题枚举变量可以保存的值取决于底层类型是否是 * fixed *:

  • 如果它是固定的,"枚举的值就是底层类型的值。"
  • 否则,最小比特字段的最小值和最大值之间的整数值可以容纳最小计数器和最大计数器。

第二种情况是,虽然代码可以在大多数编译器上运行,但最小的位字段大小为1,因此在所有兼容的C++编译器上,您可以确定的值只有0到1之间的值......

C情况

C的情况要简单得多(C11):

    • 6.2.5/16:**枚举由一组命名的整型常量值组成。每个不同的枚举组成一个不同的枚举类型。

所以基本上,它是一个整型数:

    • 6.7.2.2 ./2**定义枚举常量值的表达式应为整型常量表达式,其值可表示为int。

具有以下限制:
每个枚举类型应与char、有符号整数类型或无符号整数类型兼容。类型的选择由实现定义,但应能够表示枚举的所有成员的值。

gt0wga4j

gt0wga4j2#

在C语言中,enum类型是一个整型类型,它足够大,可以容纳所有的enum常量:
(C11,6.7.2.2p4)“每个枚举类型应该与char、有符号整数类型或无符号整数类型兼容。类型的选择是实现定义的,110)但是应该能够表示枚举的所有成员的值”。
假设enum E的选定类型为_Bool_Bool对象只能存储01_Bool对象存储不同于01的值而不调用未定义的行为是不可能的。
在这种情况下,允许编译器假设enum E类型的对象在严格符合的程序中只能保存01,因此允许优化default切换情况。

5anewei6

5anewei63#

C++标准品7.2.7 [数据库枚举]:
有可能定义一个计数,其值未被任何计数器定义。
因此,您可以拥有未在枚举器列表中列出的枚举值。
但是在你的特定情况下,“底层类型”不是“固定的”(7.2.5).规范没有说明在这种情况下哪一个是底层类型,但它必须是整数.由于char是最小的这种类型,我们可以得出结论,还有其他的枚举值没有在枚举列表中指定.
顺便说一句,我认为编译器可以优化你的情况下,当它可以确定没有其他值被赋予v,这是安全的,但我认为没有编译器是聪明的。

mepcadol

mepcadol4#

此外,7.2/10:
算术型、枚举型的表达式可以显式转换为枚举型,如果在枚举型的枚举值范围内,则值不变;否则未指定结果枚举值。

wd2eg0qa

wd2eg0qa5#

在C语言中,枚举器的类型为int,因此任何整数值都可以赋给枚举类型的对象。
来自C标准(6.7.2.2枚举说明符)
3枚举数列表中的标识符被声明为类型为int的常量,并且可以出现在任何允许的地方。
在C中,枚举数具有定义它的枚举的类型。在C中,您应该显式地指定底层类型,或者编译器自己计算允许的最大值。
来自C++标准(7.2枚举声明)
5每个枚举定义一个不同于所有其他类型的类型。每个枚举也有一个基础类型。基础类型可以使用enum-base显式指定;如果没有显式指定,则作用域枚举类型的底层类型为int。2在这些情况下,底层类型被称为fixed。3在枚举说明符的右括号后面,**每个枚举数都有其枚举的类型。
因此在C语言中,枚举的任何可能值都是任何整数值。编译器可能不会优化删除默认标签的开关。

w51jfk4q

w51jfk4q6#

在C和C++中,这是可行的。
两者代码相同:

#include <stdio.h>

enum E
{
  Foo = 0,
  Bar = 1
};

int main()
{
    enum E v = (enum E)2;    // the cast is required for C++, but not for C
    printf("v = %d\n", v);
    switch (v) {
    case Foo:
        printf("got foo\n");
        break;
    case Bar:
        printf("got bar\n");
        break;
    default:
        printf("got \n", v);
        break;
    }
}

两者的输出相同:

v = 2
got default

在C中,enum是整型,所以你可以给它赋值而不用强制转换。在C++中,enum是它自己的类型。

相关问题