C++枚举类型是有符号还是无符号的?通过推断,检查输入是否小于等于最大值并省略大于等于最小值(假设你从0开始递增1)来验证输入是否安全吗?
让我们看一下C++03标准(ISO/IEC 14882:2003)文档中7.2-5(枚举声明)的规定:
枚举类型的底层类型是可以表示所定义的所有枚举值的整数类型。除非枚举类型的某个枚举常量的值不能用int或unsigned int类型表示,否则实现可以自行选择作为枚举类型底层类型的整数类型,但是底层类型的大小不得超过int。
简而言之,编译器会根据需要选择底层类型(如果您的枚举值中有负数,则将使用带符号类型)。
你不应该依赖于任何特定的表示方式。请阅读下面的链接。此外,标准规定枚举类型使用哪种整数类型作为底层类型是由实现定义的,除非某些值无法适应int或unsigned int。
简而言之:你不能指望一个枚举类型是有符号的还是无符号的。
你不应该依赖它们是有符号的还是无符号的。如果你想要明确指定它们是有符号或无符号的,可以使用以下代码:
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
根据标准,枚举类型的底层类型是由实现定义的,不能保证其为有符号或无符号。大多数实现中,其为有符号整数。
在C++0x中将添加强类型枚举,允许您指定枚举类型的类型,例如:
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
即使现在,您仍然可以通过将枚举用作变量或参数类型来实现一些简单的验证,就像这样:
enum Fruit { Apple, Banana };
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit
// even though it has the same value as banana.
即使有些旧的答案获得了44个赞,但我不同意它们。简而言之,我认为我们不应该关心枚举类型的底层类型。
首先,在C++03标准中,枚举类型是一种独立的类型,没有符号的概念。因此,从C++03标准开始,dcl.enum
7.2 Enumeration declarations
5 Each enumeration defines a type that is different from all other types....
当我们谈论枚举类型的符号时,比如使用 <
运算符对比两个枚举操作数时,实际上是在隐式将枚举类型转换为某个整型。 关键是这个整型的符号。并且在将枚举转换为整型时,以下语句适用:
9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).
4.5 Integral promotions conv.prom
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long.
signed int
还是unsigned int
取决于signed int
是否可以包含所有定义的枚举器的值,而不是枚举的基础类型。
请参阅我的相关问题将C++枚举类型转换为整数类型后符号不正确
-Wsign-conversion
编译时,它是很重要的。我们使用它来帮助捕捉代码中意外的错误。但是要为引用标准和指出枚举没有与之关联的类型(如signed
或 unsigned
)加一点分。 - jww编译器可以决定枚举类型是有符号的还是无符号的。
另一种验证枚举类型的方法是使用枚举本身作为变量类型。例如:
enum Fruit
{
Apple = 0,
Banana,
Pineapple,
Orange,
Kumquat
};
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana.
enum { A = 1, B = 4};
使用 std::is_signed<std::underlying_type
检查 + 作用域枚举默认为 int
https://en.cppreference.com/w/cpp/language/enum 表示:
main.cpp
#include <cassert>
#include <iostream>
#include <type_traits>
enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};
int main() {
// Implementation defined, let's find out.
std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;
// Guaranteed. Scoped defaults to int.
assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));
// Guaranteed. We set it ourselves.
assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}
编译和运行:
g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main
输出:
0
在Ubuntu 16.04和GCC 6.4.0上进行测试。
虽然以上一些答案可以说是正确的,但它们并没有回答我的实际问题。编译器(gcc 9.3.0)对以下内容发出了警告:
enum FOO_STATUS {
STATUS_ERROR = (1 << 31)
};
有关使用的警告已发出:
unsigned status = foo_status_get();
if (STATUS_ERROR == status) {
enum FOO_STATUS {
STATUS_ERROR = (1U << 31)
};
1U
会使表达式变为无符号。