임베디드 면접 용어 사전
C 언어integer promotion

정수 승격

연산 전 작은 정수형이 int로 확장되는 규칙. 부호 있는/없는 타입이 섞이면 숨은 버그의 원인이 된다.

int보다 작은 정수형이 연산에 참여할 때 자동으로 int로 변환되는 규칙 (integer promotion). C의 가장 함정이 많은 부분이다.

규칙

char, short, _Bool, 비트 필드 등 int 보다 작은 타입은 연산 전에 int 로 승격된다 (int 가 모든 값을 표현할 수 있으면 int, 아니면 unsigned int)

uint8_t a = 200, b = 100;
uint8_t c = a + b;          // a, b가 int로 승격 → 300 → uint8_t로 잘려 44
int      d = a + b;         // 300 (승격된 int 그대로)

함정 ① — 비트 반전

uint8_t x = 0x0F;
uint8_t y = ~x;             // ~0x0F 는 int 연산 → 0xFFFFFFF0
                            // uint8_t 대입 시 0xF0 — 결과는 맞다

if (~x == 0xF0) { … }       // ✗ 거짓! 0xFFFFFFF0 != 0x000000F0

비교할 때 승격된 값이 그대로 쓰이므로 예상과 다르다.

if ((uint8_t)~x == 0xF0) { … }   // ✓ 명시적으로 다시 좁힌다

함정 ② — 시프트

uint8_t reg = 0x80;
uint16_t v = reg << 8;      // reg가 int로 승격 → 0x8000. 의도대로

uint32_t big = 1 << 31;     // ✗ 1은 int. 부호 비트로 넘어가 미정의 동작
uint32_t ok  = 1UL << 31;   // ✓

부호 있는 정수의 오버플로는 미정의 동작이다. 컴파일러가 "오버플로는 일어나지 않는다"고 가정하고 코드를 지워 버리는 일도 실제로 있다.

함정 ③ — 부호 있는 값과 없는 값의 비교

int      i = -1;
unsigned u = 1;

if (i < u) { … }            // ✗ 실행되지 않는다!

둘 다 int 크기이므로 승격이 아니라 "일반 산술 변환"이 적용되어 intunsigned로 변환된다. -10xFFFFFFFF = 4294967295가 되어 1보다 크다.

for (unsigned i = n - 1; i >= 0; i--) { … }   // ✗ 무한 루프
                                              //   unsigned는 항상 >= 0

부호 없는 타입으로 감소 루프를 만들면 안 된다는 것이 여기서 나온다.

함정 ④ — 8비트 MCU에서 특히 위험

// int 가 16비트인 MCU (AVR, 일부 8051)
uint16_t a = 50000, b = 50000;
uint32_t c = a + b;         // ✗ int(16비트) 연산 → 오버플로 → 잘린 값
uint32_t d = (uint32_t)a + b;   // ✓ 미리 넓힌다

int의 크기가 플랫폼마다 다르다는 점이 문제를 키운다. 32비트 MCU에서 잘 돌던 코드가 8비트로 포팅하면 깨진다.

방어 방법

① 고정 폭 타입을 쓴다 — uint8_t, int32_t (<stdint.h>)
② 연산 전에 명시적으로 캐스팅한다
③ 컴파일러 경고를 켠다
   -Wall -Wextra -Wconversion -Wsign-compare
④ MISRA C 규칙을 따른다 (필수 타입 모델)

-Wconversion이 특히 유용하다 — 암묵적 축소 변환을 전부 경고해 준다. 처음 켜면 경고가 수백 개 나오지만, 그중 진짜 버그가 섞여 있다.

왜 이런 규칙이 있나

옛 CPU에서 int가 "가장 자연스러운 연산 단위" 였기 때문이다. char 두 개를 더할 때도 어차피 레지스터로 올려 계산하므로, 언어 차원에서 그것을 규정한 것이다.

지금은 8비트 연산이 효율적인 MCU도 많아 이 규칙이 오히려 방해가 되지만, 호환성 때문에 바뀌지 않는다.

면접 답변 골격

"C는 int보다 작은 타입을 연산 전에 int로 승격합니다. 그래서 uint8_t 끼리의 ~나 비교가 예상과 다르게 동작하고, 부호 있는 값과 없는 값을 비교하면 부호 없는 쪽으로 변환되어 -1 < 1u가 거짓이 됩니다. 고정 폭 타입과 -Wconversion으로 방어합니다."

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — C 언어 핵심 — 포인터·메모리클래스·const/volatile·비트·struct 패딩