programing tip

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

itbloger 2020. 10. 5. 07:43
반응형

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,
};

which yields compilation error on my machine with 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 of ‘int’ [-Wpedantic]
         en_e_bar = +UINT64_MAX

C11 - 6.7.2.2/2

The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.

en_e_bar=UINT64_MAX is a constraint violation and this makes the above code invalid. A diagnostic message should be produce by confirming implementation as stated in the C11 draft:

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, [...]

It seems that GCC has some bug and it failed to produce the diagnostic message. (Bug is pointed in the answer by Grzegorz Szpetkowski


I took a look at the standards and my program appears to be a constraint violation in C because of 6.7.2.2p2:

Constraints: The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.

and defined in C++ because of 7.2.5:

If the underlying type is not fixed, the type of each enumerator is the type of its initializing value: — If an initializer is specified for an enumerator, the initializing value has the same type as the expression and the constant-expression shall be an integral constant expression (5.19). — If no initializer is specified for the first enumerator, the initializing value has an unspecified integral type. — Otherwise the type of the initializing value is the same as the type of the initializing value of the preceding enumerator unless the incremented value is not representable in that type, in which case the type is an unspecified integral type sufficient to contain the incremented value. If no such type exists, the program is ill-formed.

참고URL : https://stackoverflow.com/questions/41836658/enum-constants-behaving-differently-in-c-and-c

반응형