C 프로그래밍에서 상수를 표현하는 방법은 크게 두 가지입니다. 하나는 전처리기 지시문인 #define을 이용한 매크로 정의이고, 다른 하나는 const 키워드를 이용한 상수 변수 선언입니다. 두 방식은 비슷한 목적으로 사용되지만, 동작 원리와 특성에는 중요한 차이가 있습니다.
#define: 전처리기 지시문
#define은 전처리기(preprocessor) 지시문입니다. #define으로 매크로를 정의하면, 컴파일이 시작되기 전에 코드 안의 모든 매크로 이름이 해당 값으로 단순히 치환됩니다. 즉, 텍스트 수준의 문자열 대체가 일어나는 것입니다.
그렇기 때문에 컴파일러는 매크로의 존재 자체를 알지 못합니다. 컴파일러가 코드를 분석하기 전에 이미 매크로가 값으로 바뀌어 있기 때문입니다. 또한 매크로에는 타입 정보가 없으며, 정의된 위치부터 파일 끝까지 별도의 범위(scope) 제한 없이 적용됩니다.
const: 타입이 있는 상수 변수
반면 const는 실제 변수입니다. 선언하는 순간 메모리 공간을 차지하며, 컴파일러에 의해 엄격한 타입 검사가 이루어집니다. const로 선언된 변수는 이름 그대로 상수이므로 직접 값을 수정할 수 없습니다.
포인터를 활용하면 간접적으로 값을 변경하는 것이 가능하기도 하지만, 이는 C 표준에서 정의되지 않은 동작(undefined behavior)에 해당하므로 절대 사용해서는 안 됩니다.
#define과 const의 주요 차이점
- 처리 시점:
#define은 컴파일 이전의 전처리 단계에서 치환되고,const는 컴파일러가 처리하는 실제 변수입니다. - 타입 검사: 매크로는 타입이 없지만,
const변수는 명확한 자료형을 가지며 컴파일러의 타입 검사를 받습니다. - 메모리 사용: 매크로는 별도의 메모리를 차지하지 않지만,
const변수는 메모리를 할당받습니다. - 디버깅: 매크로는 치환되어 사라지기 때문에 디버거에서 확인하기 어렵지만,
const변수는 심볼 정보가 남아 있어 디버깅이 훨씬 용이합니다. - 범위: 매크로는 정의된 지점부터 파일 끝까지 유효하지만,
const변수는 일반 변수와 동일한 스코프 규칙을 따릅니다.
매크로가 항상 더 효율적일까?
일부 개발자는 매크로가 추가적인 메모리 공간을 차지하지 않기 때문에 const보다 유리하다고 생각합니다. 물론 매크로는 메모리를 소비하지 않지만, 최적화 기능을 갖춘 좋은 컴파일러라면 const 변수 역시 불필요한 메모리 접근을 줄이도록 최적화해 줍니다. 결과적으로 두 방식의 성능 차이는 거의 없으며, 실제로 매우 유사하게 동작한다고 볼 수 있습니다.
따라서 현대적인 C 코드에서는 타입 검사와 디버깅 편의성을 제공하는 const를 우선적으로 사용하고, 조건부 컴파일이나 단순 텍스트 치환이 필요한 경우에만 #define을 사용하는 것이 권장됩니다.