C 및 C ++에서 다르게 작동하는 열거 형 상수

이유 :

#include <stdio.h>
#include <limits.h>
#include <inttypes.h>

int main() {
    enum en_e {
        en_e_foo,
        en_e_bar = UINT64_MAX,
    };
    enum en_e e = en_e_foo;
    printf("%zu\n", sizeof en_e_foo);
    printf("%zu\n", sizeof en_e_bar);
    printf("%zu\n", sizeof e);
}

4 8 8C 및 8 8 8C ++로 인쇄 합니까 (4 바이트 정수가있는 플랫폼에서)?

나는 UINT64_MAX할당이 모든 열거 상수를 적어도 64 비트로 강제하지만 en_e_foo평범한 C에서는 32로 남아 있다는 인상 을 받았다 .

불일치의 근거는 무엇입니까?



답변

C에서 enum상수는 유형 int입니다. C ++에서는 열거 형입니다.

enum en_e{
    en_e_foo,
    en_e_bar=UINT64_MAX,
};

C에서 이것은 제약 조건 위반 이며 진단이 필요합니다 ( UINT64_MAX 초과하면 INT_MAX아마도 그렇게 할 것입니다). AC 컴파일러는 프로그램을 완전히 거부하거나 경고를 출력 한 다음 동작이 정의되지 않은 실행 파일을 생성 할 수 있습니다. (제약을 위반하는 프로그램이 반드시 정의되지 않은 동작을 가지고 있다는 것은 100 % 명확하지 않지만,이 경우 표준은 동작이 무엇인지 말하지 않으므로 여전히 정의되지 않은 동작입니다.)

gcc 6.2는 이에 대해 경고하지 않습니다. clang은 않습니다. 이것은 gcc의 버그입니다. 표준 헤더의 매크로가 사용될 때 일부 진단 메시지를 잘못 금지합니다. 버그 보고서를 찾아 준 Grzegorz Szpetkowski에게 감사드립니다. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71613

C ++에서 각 열거 유형에는 정수 유형 (반드시 아님 ) 인 기본 유형 이 있습니다 int. 이 기본 유형은 모든 상수 값을 나타낼 수 있어야합니다. 이 경우에, 양 en_e_fooen_e_bar타입 인 en_e경우에도 넓은 적어도 64 비트이어야 int좁다.


답변

그 코드는 처음에 유효한 C가 아닙니다.

C99 및 C11의 섹션 6.7.2.2에서는 다음과 같이 말합니다.

제약 :

열거 형 상수의 값을 정의하는 식은으로 표현할 수있는 값을 갖는 정수 상수 식이어야합니다 int.

제약 조건 위반이므로 컴파일러 진단은 필수입니다 (5.1.1.3 참조).

준수 구현은 동작이 정의되지 않음 또는 구현으로 명시 적으로 지정 되더라도 전처리 번역 단위 또는 번역 단위에 구문 규칙 또는 제약 위반이 포함 된 경우 적어도 하나의 진단 메시지 (구현 정의 방식으로 식별 됨)를 생성해야합니다. 한정된.


답변

에서 C A는 동안, enum별도의 유형으로 간주되고, 그 자체가 항상 유형이 열거 int.

C11-6.7.2.2 열거 지정자

3 열거 자 목록의 식별자는 int 유형의 상수로 선언됩니다.

따라서 표시되는 동작은 컴파일러 확장입니다.

값이 너무 큰 경우 열거 자 중 하나의 크기 만 확장하는 것이 합리적이라고 말하고 싶습니다.


반면에 C ++에서는 모든 열거 자에 enum선언 된 형식이 있습니다.

따라서 모든 열거 자의 크기는 동일해야합니다. 따라서 전체 크기 enum가 확장되어 가장 큰 열거자를 저장합니다.


답변

다른 사람들이 지적했듯이 제약 조건 위반으로 인해 코드 형식이 잘못되었습니다 (C에서).

GCC 버그 # 71613 (2016 년 6 월보고 됨)이 있는데, 이는 일부 유용한 경고가 매크로로 침묵된다는 것을 나타냅니다.

시스템 헤더의 매크로를 사용하면 유용한 경고가 표시되지 않는 것 같습니다. 예를 들어 아래 예에서 경고는 두 열거 형 모두에 유용하지만 하나의 경고 만 표시됩니다. 다른 경고에 대해서도 마찬가지 일 수 있습니다.

현재 해결 방법은 매크로 앞에 단항 +연산자 를 추가하는 것입니다 .

enum en_e {
   en_e_foo,
   en_e_bar = +UINT64_MAX,
};

GCC 4.9.2를 사용하는 내 컴퓨터에서 컴파일 오류가 발생합니다.

$ gcc -std=c11 -pedantic-errors -Wall main.c
main.c: In function ‘main’:
main.c:9:20: error: ISO C restricts enumerator values to range ofint’ [-Wpedantic]
         en_e_bar = +UINT64_MAX


답변

C11-6.7.2.2/2

열거 상수의 값을 정의하는 표현식은 int.

en_e_bar=UINT64_MAX제약 조건 위반이며 이로 인해 위 코드가 무효화됩니다. C11 초안에 명시된대로 구현을 확인하여 진단 메시지를 생성해야합니다.

적합한 구현은 전처리 번역 단위 또는 번역 단위가 구문 규칙 또는 제약의 위반을 포함하는 경우 적어도 하나의 진단 메시지 (구현 정의 방식으로 식별 됨)를 생성해야합니다. […]

GCC에 버그가있어 진단 메시지를 생성하지 못한 것 같습니다. (버그가에서 가리키는 대답 하여 그르 Szpetkowski


답변

나는 표준을 살펴 보았고 내 프로그램은 6.7.2.2p2 때문에 C에서 제약 위반으로 보입니다 .

제약 : 열거 형 상수의 값을 정의하는 표현식은 정수로 표현할 수있는 값을 갖는 정수 상수 표현식이어야합니다.

7.2.5 때문에 C ++에서 정의되었습니다.

기본 유형이 고정되지 않은 경우 각 열거 자의 유형은 초기화 값의 유형입니다. — 열거 자에 대해 이니셜 라이저가 지정된 경우 초기화 값은 표현식과 동일한 유형을 가지며 상수 표현식은 정수 여야합니다. 상수 표현 (5.19). — 첫 번째 열거 자에 대해 이니셜 라이저가 지정되지 않은 경우 초기화 값에는 지정되지 않은 정수 유형이 있습니다. — 그렇지 않으면 초기화 값의 유형은 증가 된 값이 해당 유형에서 표현할 수없는 경우 이전 열거 자의 초기화 값 유형과 동일합니다.이 경우 유형은 증가 된 값을 포함하기에 충분한 지정되지 않은 정수 유형입니다. 그러한 유형이 없으면 프로그램이 잘못된 것입니다.


답변


이 글은 C++ 카테고리에 분류되었고 , 태그가 있으며 님에 의해 에 작성되었습니다.