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 8
와 C로에서.8 8 8
C++ (4바이트 인트가 있는 플랫폼)에서?
을 받았다.UINT64_MAX
할당은 모든 열거 수 수 수 수 수 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64en_e_foo
평원 C에 32에 남아 있다.
그 불일치에 대한 근거는 무엇인가?
C에서는enum
상수는 유형이다.int
C++에서는 열거형이다.
enum en_e{
en_e_foo,
en_e_bar=UINT64_MAX,
};
C에서 이것은 제약조건 위반으로, 진단이 필요하다(만약 UINT64_MAX
초과하다INT_MAX
, 그것은 아마도 매우 할 것이다.C 컴파일러는 프로그램을 완전히 거부하거나 경고를 인쇄한 다음 동작이 정의되지 않은 실행 파일을 생성할 수 있다.(제약을 위반하는 프로그램이 반드시 정의되지 않은 행동을 한다는 것은 100% 명확하지 않지만, 이 경우 표준은 그 행동이 무엇인지 말하지 않기 때문에 그것은 여전히 정의되지 않은 행동이다.)
gcc 6.2는 이것에 대해 경고하지 않는다. clang은 경고한다.이것은 gcc의 버그로, 표준 헤더에서 매크로가 사용될 때 일부 진단 메시지를 잘못 억제한다.Grzegorz Szpetkowski가 버그 보고서를 찾아줘서 고마워: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71613
C++에서 각 열거형에는 기본형(일부 정수형일 필요는 없음)이 있다.int
이 기본 형식은 모든 상수 값을 나타낼 수 있어야 한다.그래서 이 경우에는 둘 다en_e_foo
그리고en_e_bar
활자가 있다en_e
, 폭은 적어도 64비트여야 한다.int
폭이 좁다
그 코드는 애초에 C가 유효하지 않다.
C99와 C11의 섹션 6.7.2.2는 다음과 같이 말한다.
제약 조건:
수정의 값으로 수 있는 .
int
.
컴파일러 진단은 제약 조건 위반이기 때문에 필수 사항이다. 5.1.1.3:
동작이 정의되지 않았거나 구현 정의되지 않은 것으로 명시적으로 지정되었더라도 사전 처리 번역 단위 또는 번역 단위가 구문 규칙이나 제약 조건을 위반하는 경우(구현 정의 방식으로 식별됨)에 대해 적어도 하나의 진단 메시지를 생성해야 한다.
C에서, 한편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 of ‘int’ [-Wpedantic]
en_e_bar = +UINT64_MAX
C11 - 6.7.2.2/2
수 있는 .
int
.
en_e_bar=UINT64_MAX
제약 조건 위반이며 이는 위의 코드를 무효로 만든다.진단 메시지는 C11 초안에 명시된 대로 구현을 확인함으로써 생성되어야 한다.
사전 처리된 번역 단위 또는 번역 단위가 구문 규칙이나 제약 조건을 위반하는 경우, 적합한 구현은 적어도 하나 이상의 진단 메시지를 생성해야 한다[...]
GCC에 버그가 있는 것 같은데 진단 메시지를 못 낸 것 같다.(그르제고르츠 스즈페트코프스키의 대답에 버그가 지목된다.
나는 표준을 살펴봤는데 내 프로그램은 6.7.2.2p2로 인해 C에서 제약조건 위반으로 보인다.
제약 조건:열거 상수의 값을 정의하는 식은 int로 나타낼 수 있는 값을 갖는 정수 상수 식이어야 한다.
그리고 7.2.5 때문에 C++로 정의된다.
기본 형식이 고정되지 않은 경우, 각 열거자의 유형은 초기화 값의 유형이다: — 열거자에 대해 이니셜라이저를 지정한 경우 초기화 값은 식과 동일한 유형을 가지며, 상수 표현은 정수 표현식(5.19)이어야 한다.— 첫 번째 열거자에 대해 이니셜라이저를 지정하지 않은 경우, 초기화 값은 지정되지 않은 정수 유형을 갖는다.— 그렇지 않은 경우, 증가된 값을 해당 유형에서 나타낼 수 없는 경우, 증가된 값을 포함하기에 충분한 불특정 적분 형식이 아닌 한, 초기화 값의 유형은 선행 열거자의 초기화 값 유형과 동일하다.이러한 유형이 존재하지 않으면 프로그램의 형식이 잘못된다.
참조URL: https://stackoverflow.com/questions/41836658/enum-constants-behaving-differently-in-c-and-c
'IT이야기' 카테고리의 다른 글
포인터 설명에 대한 포인터 (0) | 2022.04.16 |
---|---|
C에서 무료와 몰록은 어떻게 작동하는가? (0) | 2022.04.16 |
vue 구성 요소의 CSRf 토큰 (0) | 2022.04.14 |
실행자.newCacheThreadPool() 대 실행자.newFixed스레드풀() (0) | 2022.04.14 |
Vue 테스트 유틸리티가 구성 요소 데이터를 업데이트하지만 돔을 다시 렌더링하지 않는 경우 (0) | 2022.04.14 |