C ++ 열거 형이 서명되었거나 서명되지 않았습니까? 그리고 확장에 의해 입력이 <= 최대 값인지 확인하고> = 최소 값을 제외하는 것이 안전합니까 (0에서 시작하고 1 씩 증가한다고 가정)?
C ++ 열거 형이 서명되었거나 서명되지 않았습니까? 그리고 확장에 의해 입력이 <= 최대 값인지 확인하고> = 최소 값을 제외하는 것이 안전합니까 (0에서 시작하고 1 씩 증가한다고 가정)?
답변:
특정 표현에 의존해서는 안됩니다. 다음 링크를 읽으십시오 . 또한 표준은 어떤 값이 int 또는 unsigned int에 맞지 않는 한 int보다 클 수 없다는 점을 제외하고는 enum의 기본 유형으로 사용되는 정수 유형이 구현 정의되어 있다고 말합니다.
요컨대, 서명되거나 서명되지 않은 열거 형에 의존 할 수 없습니다.
소스로 가자. 다음은 C ++ 03 표준 (ISO / IEC 14882 : 2003) 문서가 7.2-5 (열거 선언)에서 말하는 내용입니다.
열거 형의 기본 형식은 열거 형에 정의 된 모든 열거 자 값을 나타낼 수있는 정수 형식입니다. 열거 자의 값이 int 또는 unsigned int에 맞지 않는 한 기본 유형이 int보다 클 수 없다는 점을 제외하면 열거 형의 기본 유형으로 사용되는 정수 유형은 구현에 따라 정의됩니다.
요컨대, 컴파일러는 선택할 수 있습니다 (분명히 일부 열거 값에 대해 음수가 있으면 서명됩니다).
서명 여부에 의존해서는 안됩니다. 명시 적으로 서명하거나 서명하지 않으려면 다음을 사용할 수 있습니다.
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 개의 찬성표를 받았지만 모든 답변에 동의하지 않는 경향이 있습니다. 요컨대, 우리가 underlying type
열거 형 에 대해 신경 써야한다고 생각하지 않습니다 .
먼저 C ++ 03 Enum 유형은 부호 개념이없는 고유 한 유형입니다. C ++ 03 표준부터dcl.enum
7.2 Enumeration declarations
5 Each enumeration defines a type that is different from all other types....
따라서 열거 형 유형의 부호에 대해 이야기 할 때, 예를 들어 <
연산자를 사용하여 두 개의 열거 형 피연산자를 비교할 때 실제로 열거 형 유형을 정수 유형으로 암시 적으로 변환하는 것에 대해 이야기하고 있습니다. 중요한 것은이 통합 유형의 표시입니다 . enum을 정수 유형으로 변환 할 때 다음 문이 적용됩니다.
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
-Wsign-conversion
. 코드에서 의도하지 않은 실수를 포착하는 데 사용합니다. 그러나 표준을 인용하고 열거 형에 연결된 유형 ( 대 ) 이 없음을 지적하면 +1 합니다. signed
unsigned
앞으로 C ++ 0x에서는 강력한 형식의 열거 를 사용할 수 있으며 몇 가지 장점 (예 : 형식 안전성, 명시 적 기본 형식 또는 명시 적 범위 지정)이 있습니다. 그것으로 당신은 유형의 표시를 더 잘 확신 할 수 있습니다.
다른 사람들이 이미 서명 된 / 서명되지 않은 것에 대해 말한 것 외에도 열거 형 유형의 범위에 대해 표준이 말하는 내용은 다음과 같습니다.
7.2 (6) : "e (min)가 가장 작은 열거 자이고 e (max)가 가장 큰 열거 형의 경우 열거 형 값은 b (min)에서 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입니다. 관심이 있다면 컴파일러 문서를 확인하세요 (예를 들어 열거 자 이외의 정수 값을 열거 형의 경우 값이 열거 형 범위에 있는지 여부를 알아야합니다 (결과 열거 형 값이 지정되지 않은 경우).
이러한 값이 함수에 대한 유효한 입력인지 여부는 열거 유형의 유효한 값인지 여부와 다른 문제 일 수 있습니다. 확인 코드는 아마도 후자보다는 전자에 대해 걱정하고 있으므로이 예제에서는 적어도> = 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>()));
}
컴파일 및 실행 :
g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main
산출:
0
Ubuntu 16.04, GCC 6.4.0에서 테스트되었습니다.