문제

C ++ 열거가 서명되거나 서명되지 않습니까? 그리고 확장하여 <= 최대 값인지 확인하여 입력을 검증하고 최소값을 남기고 최소값 (0에서 시작하여 1로 증가했다고 가정)을 확인하는 것이 안전합니까?

도움이 되었습니까?

해결책

특정 표현에 의존해서는 안됩니다. 다음을 읽으십시오 링크. 또한 표준에 따르면 일부 값이 int 또는 부호없는 int에 맞지 않는 한 int보다 크지 않다는 점을 제외하고는 열거의 기본 유형으로 사용되는 적분 유형이 구현 정의되어 있다고 말합니다.

요컨대 : 당신은 서명하거나 서명되지 않은 열거에 의존 할 수 없습니다.

다른 팁

소스로 가자. C ++ 03 표준 (ISO/IEC 14882 : 2003) 문서가 7.2-5 (열거 선언)에 표시됩니다.

열거의 기본 유형은 열거에 정의 된 모든 열거 자 값을 나타낼 수있는 적분 유형입니다. 열거 자의 값이 int 또는 부호없는 int에 맞지 않는 한, 기본 유형이 int보다 크지 않아야한다는 점을 제외하고 열거의 기본 유형으로 사용되는 적분 유형으로 사용되는 구현 정의된다.

요컨대, 컴파일러가 선택하게됩니다 (분명히, 일부 ennumeration 값에 대해 음수가있는 경우 서명됩니다).

서명하거나 서명되지 않은 것에 의존해서는 안됩니다. 명시 적으로 서명하거나 서명되지 않은 경우 다음을 사용할 수 있습니다.

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

서명하거나 서명되지 않은 것에 의존해서는 안됩니다. 표준에 따르면 이는 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.

컴파일러는 열거가 서명되었는지 여부를 결정할 수 있습니다.

열거를 검증하는 또 다른 방법은 열거 자체를 가변 유형으로 사용하는 것입니다. 예를 들어:

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.

오래된 답변조차도 44 개의 upvotes를 얻었고, 나는 그들 모두에 동의하지 않는 경향이 있습니다. 요컨대, 나는 우리가 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).

그리고 분명히, 열거의 기본 유형은 적분 촉진과 아무 관련이 없습니다. 표준은 다음과 같이 적분 촉진을 정의하기 때문에 다음과 같습니다.

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 ++ 열거 유형의 부호가 적분 유형으로 변환 한 후 잘못되었습니다.

앞으로 C ++ 0x, 강력하게 타이핑 된 열거 이용 가능하며 몇 가지 장점 (예 : 유형 안전, 명시 적 기본 유형 또는 명시 적 범위)이 있습니다. 이를 통해 당신은 유형의 표시를 더 잘 보장 할 수 있습니다.

다른 사람들이 서명/부호없는 것에 대해 이미 말한 것 외에도, 표준이 열거 된 유형의 범위에 대해 말하는 내용은 다음과 같습니다.

7.2 (6) : "E (Min)가 가장 작은 열거 자이고 E (Max)가 가장 큰 열거의 경우, 열거의 값은 범위 B (최소)에서 B (max) 범위의 기본 유형의 값입니다. ), 여기서 b (min) 및 b (max)는 각각 e (min) 및 e (max)를 저장할 수있는 가장 작은 비트 필드의 가장 작고 가장 큰 값입니다. 정의되지 않은 값이없는 열거를 정의 할 수 있습니다. 열거 자 중 하나에 의해. "

예를 들어 :

enum { A = 1, B = 4};

E (min)가 1이고 E (Max)가 4 인 열거 된 유형을 정의합니다. 기본 유형이 int로 서명되면 가장 작은 비트 필드에는 4 비트가 있고 구현의 int가 2의 보완 인 경우 유효한 범위입니다. 열거는 -8 ~ 7입니다. 기본 유형이 서명되지 않은 경우 3 비트가 있고 범위는 0 ~ 7입니다. 관리하는 경우 컴파일러 문서를 확인하십시오 (예를 들어 열거 자 이외의 통합 값을 제시하려는 경우에 따라 열거 된 유형은 값이 열거 범위에 있는지 여부를 알아야합니다. 결과 열거 값이 지정되지 않은 경우).

이러한 값이 기능에 유효한 입력인지 여부는 열거 된 유형의 유효한 값인지 여부와 다른 문제 일 수 있습니다. 귀하의 검사 코드는 아마도 후자보다는 전자에 대해 걱정할 수 있으므로이 예에서는 최소한> = a 및 <= b를 확인해야합니다.

확인하십시오 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 상류.

컴파일 및 실행 :

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

산출:

0

우분투 16.04, GCC 6.4.0에서 테스트.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top