C ++枚举是签名还是未签名?

时间:2008-10-01 18:33:04

标签: c++ enums

C ++枚举是签名还是未签名?通过扩展,通过检查输入是< =你的最大值来验证输入是安全的,并且省略> =你的最小值(假设你从0开始并递增1)?

9 个答案:

答案 0 :(得分:99)

让我们去看看源头。这是C ++ 03标准(ISO / IEC 14882:2003)文档在7.2-5(枚举声明)中所说的内容:

  

枚举的基础类型   是一种可以代表的整体类型   中定义的所有枚举器值   枚举。它是   实现 - 定义哪个积分   type用作底层类型   列举除了   基础类型不应该更大   比int除非a的值   枚举器不能适合int或   unsigned int。

简而言之,您的编译器可以选择(显然,如果您的某些枚举值有负数,则会被签名)。

答案 1 :(得分:59)

您不应该依赖任何特定的陈述。阅读以下link。此外,标准说它是实现定义的,哪个整数类型用作枚举的基础类型,除了它不应大于int,除非某些值不能适合int或unsigned int。

简而言之:你不能依赖于签名或未签名的枚举。

答案 2 :(得分:21)

您不应该依赖签名或未签名。如果要明确签名或未签名,可以使用以下命令:

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum

答案 3 :(得分:14)

您不应该依赖签名或未签名。根据标准,它是实现定义的,其中整数类型用作枚举的基础类型。但是,在大多数实现中,它是一个有符号整数。

在C ++中将添加strongly typed enumerations,这将允许您指定枚举的类型,例如:

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.

答案 4 :(得分:5)

编译器可以决定枚举是否有符号或无符号。

验证枚举的另一种方法是使用枚举本身作为变量类型。例如:

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.

答案 5 :(得分:5)

即使是一些旧答案也有44个赞成票,我倾向于不同意所有这些答案。简而言之,我认为我们不应该关心枚举的underlying type

首先,C ++ 03枚举类型是一种独特的类型,没有符号概念。从C ++ 03标准dcl.enum

开始
7.2 Enumeration declarations 
5 Each enumeration defines a type that is different from all other types....

因此,当我们讨论枚举类型的符号时,比如使用<运算符比较2个枚举操作数时,我们实际上是在讨论将枚举类型隐式转换为某种整数类型。 重要的是这种整体类型的标志。当将枚举转换为整数类型时,此语句适用:

9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).

而且,显然,枚举的基本类型与积分促销无关。由于标准定义了Integral Promotion,如下所示:

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是否可以包含定义的枚举数的所有值,而不是枚举的基础类型。

查看我的相关问题 Sign of C++ Enum Type Incorrect After Converting to Integral Type

答案 6 :(得分:4)

将来,使用C ++ 0x,strongly typed enumerations将可用并具有多个优点(例如类型安全,显式底层类型或显式范围)。有了这个,你可以更好地确定类型的标志。

答案 7 :(得分:4)

除了其他人已经说过的有关签名/未签名的内容之外,以下是关于枚举类型范围的标准说明:

7.2(6):“对于枚举,其中e(min)是最小的枚举数且e(max)是最大的,枚举的值是b(min)到b的范围内的基础类型的值b(max),其中b(min)和b(max)分别是可以存储e(min)和e(max)的最小位域的最小值和最大值。可以定义一个枚举其值不是由任何普查员定义的。“

例如:

enum { A = 1, B = 4};

定义了枚举类型,其中e(min)为1,e(max)为4.如果基础类型为signed int,则所需的最小位域为4位,如果实现中的int为2的补码,则枚举的有效范围是-8到7.如果基础类型是无符号的,那么它有3位,范围是0到7.如果你关心,请检查编译器文档(例如,如果你想要转换除了枚举类型的枚举器,然后您需要知道该值是否在枚举范围内 - 如果不是未指定的结果枚举值。

这些值是否是函数的有效输入可能与它们是否是枚举类型的有效值有所不同。您的检查代码可能会担心前者而不是后者,因此在此示例中至少应检查&gt; = A和&lt; = B。

答案 8 :(得分:0)

使用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>()));
}

GitHub upstream

编译并运行:

g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main

输出:

0

在Ubuntu 16.04,GCC 6.4.0上进行了测试。