상수 표현식
상수 표현식 (Constant expressions)
C에는 상수 표현식(constant expression) 이라고 불리는 여러 종류의 표현식이 있어요. 이름만 봐서는 하나인 것 같지만, 실제로는 용도에 따라 조금씩 다른 종류가 있고, 각각 어디에 쓸 수 있는지가 정해져 있어요. 이 페이지에서 그 종류들을 정리해 볼게요.
출처: cppreference
본문
전처리기 상수 표현식 (Preprocessor constant expression)
#if나 #elif 다음에 오는 표현식은 다음으로 확장되어야 해요.
#if 표현식에서 평가될 때 문자 상수는 소스 문자 집합, 실행 문자 집합, 또는 다른 구현 정의 문자 집합으로 해석될 수 있어요.
#if 표현식의 정수 산술은 부호 있는 타입에는 intmax_t의, 부호 없는 타입에는 uintmax_t의 의미론을 사용해 수행돼요. |
(since C99) |
정수 상수 표현식 (Integer constant expression)
정수 상수 표현식은 다음만으로 구성된 표현식이에요.
- 대입, 증가·감소, 함수 호출, 쉼표가 아닌 연산자. 단, 캐스트 연산자는
sizeof,_Alignof(until C23) /alignas(since C23),typeof/typeof_unqual(since C23) 연산자의 피연산자의 일부가 아닌 한 산술 타입을 정수 타입으로만 캐스트할 수 있어요. - 정수 상수
- 열거형 상수
- 문자 상수
- 부동 상수. 단, 즉시 정수 타입으로의 캐스트의 피연산자로 사용될 때만
- 피연산자가 VLA가 아닌 sizeof 연산자 (since C99)
_Alignof(until C23) / alignof(since C23) 연산자 |
(since C11) |
| 정수 타입이거나, 산술 타입이면서 캐스트의 즉시 피연산자인 이름 있는 및 복합 리터럴 상수 | (since C23) |
정수 상수 표현식은 컴파일 타임에 평가돼요. 다음 문맥들은 정수 상수 표현식 으로 알려진 표현식을 요구해요.
| 배열 지정자(designator)의 인덱스 | (since C99) |
_Static_assert의 첫 번째 인자, _Alignof(until C23) / alignof(since C23)의 정수 인자 |
(since C11) |
비트 정밀 정수 타입(_BitInt(N))의 비트 수 N |
(since C23) |
정적 초기화식 (Static initializer)
정적 및 thread_local 저장 기간의 객체나, constexpr 저장 클래스 지정자(since C23)로 선언된 객체의 초기화에 쓰이는 표현식은 문자열 리터럴이거나 다음 중 하나일 수 있는 표현식이어야 해요.
_Alignof(until C23) / alignof(since C23) 연산자 |
(since C11) |
| 산술 타입의 이름 있는 또는 복합 리터럴 상수 | (since C23) |
5) 이름 있는 상수(named constant) — 열거형 상수이거나, true·false·nullptr 중 하나인 미리 정의된 상수이거나, constexpr 저장 클래스 지정자로 선언되고 객체 타입을 가진 식별자, 또는 구조체·공용체 타입의 이름 있는 상수에 . 멤버 접근 연산자를 적용한 후위 표현식(재귀적으로도 가능). 6) 복합 리터럴 상수(compound literal constant) — constexpr 저장 클래스 지정자를 가진 복합 리터럴, 또는 구조체·공용체 타입의 복합 리터럴 상수에 . 멤버 접근 연산자를 적용한 후위 표현식(재귀적으로도 가능). 구조체 또는 공용체 상수는 각각 구조체 또는 공용체 타입의 이름 있는 상수나 복합 리터럴 상수예요. . 멤버 접근 연산자가 공용체 상수의 멤버에 접근한다면, 접근하는 멤버는 그 공용체 상수의 초기화자에 의해 초기화되는 멤버와 같아야 해요. |
(since C23) |
정수 상수 표현식과 달리, 정적 초기화식은 반드시 컴파일 타임에 평가될 필요는 없어요. 컴파일러는 그런 초기화식을 프로그램 시작 전에 호출되는 실행 코드로 바꿀 자유가 있어요.
static int i = 2 || 1 / 0; // i를 값 1로 초기화
| 이 섹션은 불완전해요. 사유: 다른 미니 예제 없음 |
부동소수점 정적 초기화식의 값은 런타임에 실행된 같은 표현식의 값보다 덜 정확할 수는 없지만, 더 정확할 수도 있어요.
부동소수점 상수 표현식 (Floating-point constant expressions)
정적 초기화식에 사용되지 않는 부동소수점 타입의 산술 상수 표현식은 항상 런타임 중에 평가된 것처럼 동작해요. 현재 반올림(FENV_ACCESS가 켜져 있다면)의 영향을 받고, math_errhandling에 지정된 대로 오류를 보고해요.
void f(void)
{
#pragma STDC FENV_ACCESS ON
static float x = 0.0 / 0.0; // 정적 초기화식: 예외를 발생시키지 않음
float w[] = { 0.0 / 0.0 }; // 예외를 발생시킴
float y = 0.0 / 0.0; // 예외를 발생시킴
double z = 0.0 / 0.0; // 예외를 발생시킴
}
주의 (Notes)
표현식이 그 타입으로 표현할 수 없는 값으로 평가된다면, 상수 표현식으로 사용할 수 없어요.
구현이 다른 형태의 상수 표현식을 받아들일 수도 있어요. 그러나 그런 상수 표현식은 정수 상수 표현식, 산술 상수 표현식, 또는 주소 상수 표현식으로 간주되지 않으므로, 그런 종류의 상수 표현식을 요구하는 문맥에서 쓸 수 없어요. 예를 들어 int arr[(int)+1.0];는 VLA를 선언해요.
더 알아보기
- 정수 상수 · 부동 상수 · 문자 상수 — 상수 표현식을 이루는 리터럴들
- enum — 열거형 상수와 정수 상수 표현식의 관계
- 침묵의 변환 (implicit conversion) — 정수에서 포인터로의 변환 등
- C++ documentation for Constant expressions