枚举上提供的类型检查

发布于 2024-08-03 06:09:18 字数 446 浏览 1 评论 0原文

我希望下面的代码片段会抱怨尝试将 0,1,2 之外的其他值分配给 Color 变量。 但以下内容确实可以编译,并且我得到输出

Printing:3

3

有人能解释为什么吗?枚举不应该是真正的用户定义类型吗?谢谢。

enum Color { blue=0,green=1,yellow=2};

void print_color(Color x);

int main(){
    Color x=Color(3);

    print_color(x);
    std::cout << x << std::endl;

    return 0;
}

void print_color(Color x)
{
    std::cout << "Printing:" << x << std::endl;
}

I would expect the following code snippet to complain about trying to assign something other that 0,1,2 to a Color variable.
But the following does compile and I get the output

Printing:3

3

Can anybody explain why? Is enum not meant to be a true user-defined type? Thanks.

enum Color { blue=0,green=1,yellow=2};

void print_color(Color x);

int main(){
    Color x=Color(3);

    print_color(x);
    std::cout << x << std::endl;

    return 0;
}

void print_color(Color x)
{
    std::cout << "Printing:" << x << std::endl;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

記憶穿過時間隧道 2024-08-10 06:09:18

由于您手动将 3 转换为 Color,编译器将允许您执行此操作。如果您尝试使用普通的 3 而不进行强制转换来初始化变量 x,您将得到诊断信息。

请注意,枚举可以存储的值的范围不受其包含的枚举数的限制。它是可以存储枚举的所有枚举值的最小位域的值范围。也就是说,枚举类型的范围是 0..3

00
01
10
11

因此值 3 仍在范围内,因此代码有效。如果您转换 4,则 C++ 标准将未指定结果值。

实际上,实现必须为枚举选择底层整数类型。它可以选择的最小类型是 char,但它仍然能够至少存储最大 127 的值。但如前所述,编译器不需要将 4 转换为 4 值,因为它超出了枚举范围。


我想我应该对“基础类型”和“枚举值范围”的区别发表一些解释。任何类型的值范围都是该类型的最小值和最大值。枚举的基础类型必须能够存储任何枚举器的值(当然) - 并且具有相同基础类型的两个枚举是布局兼容的(这在发生类型不匹配的情况下提供了一定的灵活性)。

因此,虽然底层类型旨在修复对象表示(对齐和大小),但枚举的值在 7.2/6 中定义如下

对于 emin 是最小枚举数、emax 是最大枚举数的枚举,枚举的值是 b 范围内基础类型的值min 到 bmax,其中 bmin 和 bmax 分别是可以存储 emin 和 emax 的最小位字段。可以定义一个具有未由任何枚举器定义的值的枚举。

[脚注:在补码机器上,bmax 是大于或等于 max (abs(emin) − 1 ,abs(emax)) 形式
2M−1;如果 emin 为非负且 −(bmin+1),则 bmin 为零 否则。]

Since you manually cast the 3 to Color, the compiler will allow you to do that. If you tried to initialize the variable x with a plain 3 without a cast, you would get a diagnostic.

Note that the range of values an enumeration can store is not limited by the enumerators it contains. It's the range of values of the smallest bitfield that can store all enumerator values of the enumeration. That is, the range of your enumeration type is 0..3:

00
01
10
11

The value 3 is thus still in range, and so the code is valid. Had you cast a 4, then the resulting value would be left unspecified by the C++ Standard.

In practice, the implementation has to chose an underlying integer type for the enumeration. The smallest type it can choose is char, but which is still able to at least store values ranging up to 127. But as mentioned, the compiler is not required to convert a 4 to a value of 4, because it's outside the range of your enumeration.


I figure i should post some explanation on the difference of "underlying type" and "range of enumeration values". The range of values for any type is the smallest and largest value of that type. The underlying type of an enumeration must be able to store the value of any enumerator (of course) - and two enumerations that have the same underlying type are layout compatible (this allows some flexibility in case a type mismatch occurs).

So while the underlying type is meant to fix the object representation (alignment and size), the values of the enumeration is defined as follows in 7.2/6

For an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values of the underlying type in the range bmin to bmax, where bmin and bmax are, respectively, the smallest and largest values of the smallest bit-field that can store emin and emax . It is possible to define an enumeration that has values not defined by any of its enumerators.

[Footnote: On a two’s-complement machine, bmax is the smallest value greater than or equal to max (abs(emin) − 1 ,abs(emax)) of the form
2M−1; bmin is zero if emin is non-negative and −(bmin+1) otherwise.]

紙鸢 2024-08-10 06:09:18

Color(3) 是一个强制转换,与 (Color)3 具有相同的语义,它不是构造函数。请注意,您还可以使用 static_cast(3) 进行相同的转换,但不能使用 Color x(3)

Color(3) is a cast, with the same semantic as (Color)3, it isn't a constructor. Note that you can also use static_cast<Color>(3) for the same conversion but you can't use Color x(3).

绝對不後悔。 2024-08-10 06:09:18

从编译时检查的角度来看,C++ 中的枚举更像是一组命名的整数常量,而不是真正的类型。然而,C++ 标准有这样的说法 [dcl.enum]:

9 算术或枚举类型的表达式可以转换为
显式枚举类型。如果该值位于
枚举类型的枚举值范围;否则
结果枚举值未指定。

“未指定”比通常的“未定义行为”稍好一些。

Enum in C++ is more of a set of named integer constants than a true type, from compile-time checking point of view. However, the C++ standard has this to say [dcl.enum]:

9 An expression of arithmetic or enumeration type can be converted to an
enumeration type explicitly. The value is unchanged if it is in the
range of enumeration values of the enumeration type; otherwise the
resulting enumeration value is unspecified.

"Unspecified" is slightly better than the usual "undefined behavior".

热情消退 2024-08-10 06:09:18

C 和 C++ 标准在枚举主题上都有点令人困惑。两者都坚持认为枚举是“不同的类型”,但随后都将它们视为基础整数类型。 C++ 甚至引用了一个斜体术语“底层类型”,它只是在引入 wchar_t 时才定义的。

总之,wchar_t 和 enum 类型是“不同的”,但只是映射到实现选择的底层整型类型,毫无疑问,这是因为需要与历史枚举兼容,而历史枚举绝对只是一个 int。

现代编译器通常可以选择向枚举添加更多类似类型的行为,从而针对各种误用打开警告和错误。这些不能是默认行为,因为它们选择了不合格的行为。

Both the C and the C++ standards are kind of confusing on the subject of enums. Both insist that enums are "distinct types" but then both treat them as the underlying integral type. C++ even refers to an italic term "underlying type" which is only sort-of defined when introducing wchar_t.

In summary, wchar_t and enum types are "distinct" but simply mapped to an underlying integral type chosen by the implementation, and this is no doubt due to the need to be compatible with historical enum which was definitely just an int.

Modern compilers typically have options to add more type-like behavior to enums, turning on warnings and errors for various misuses. These can't be a default because they elect non-conforming behavior.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文