C++에서 #변수명 사용법 - 스트링화 연산자
C++에서 가끔 #을 붙여 쓰는 매크로 인자를 봤는데 오늘 용도를 알았다. 스트링화 연산자(stringizing operator) 라고 부른다.
2026년 수정 안내 원래 이 글에는 “
#a는 변수명인 aaa의 값이 찍힌다”고 적혀 있었는데 앞뒤가 모순된 설명이었다.#a가 만드는 것은 문자열"aaa"다. 값과는 무관하다. 설명을 바로잡고##연산자도 함께 정리한다.
# — 인자를 문자열로 바꾼다
#include <cstdio>
#define Test(a) { printf( "%s\n", #a ); }
int main()
{
int aaa = 1000;
Test( aaa ); // "aaa" 가 출력된다. 1000이 아니다.
return 0;
}
#a는 전처리 단계에서 매크로 인자로 들어온 토큰을 그대로 문자열 리터럴로 바꾼다. 위 코드는 전처리 후 printf("%s\n", "aaa");가 된다. 변수 aaa의 값 1000은 전처리기가 알지도 못하고, 알 필요도 없다.
식을 그대로 넘겨도 마찬가지다.
Test( a + b * 2 ); // "a + b * 2" 가 출력된다
어디에 쓰나
변수명이나 식을 로그에 그대로 남기고 싶을 때 유용하다. 간이 assert를 만들 때가 대표적이다.
#define CHECK( expr ) \
do { \
if ( !( expr ) ) \
printf( "CHECK FAILED: %s (%s:%d)\n", #expr, __FILE__, __LINE__ ); \
} while ( 0 )
CHECK( ptr != nullptr );
// 실패 시 → CHECK FAILED: ptr != nullptr (main.cpp:42)
로그 라이브러리에서 클래스 이름을 태그로 출력할 때도 자주 쓰인다.
## — 토큰을 붙인다
#과 짝을 이루는 연산자로 토큰 붙이기 연산자(token-pasting operator) 인 ##이 있다. 좌우 토큰을 이어붙여 하나의 식별자를 만든다.
#define DECLARE_VAR( name ) int var_##name = 0;
DECLARE_VAR( count ); // int var_count = 0;
DECLARE_VAR( index ); // int var_index = 0;
주의할 점
매크로를 한 번 더 거쳐야 값이 펼쳐진다. #은 인자를 펼치지 않고 그대로 문자열로 만들기 때문에, 매크로 상수를 문자열로 바꾸려면 단계를 하나 더 둬야 한다.
#define VERSION 3
#define STR_DIRECT( x ) #x
#define STR( x ) STR_DIRECT( x )
printf( "%s\n", STR_DIRECT( VERSION ) ); // "VERSION" ← 펼쳐지지 않는다
printf( "%s\n", STR( VERSION ) ); // "3" ← 한 단계 거쳐 펼쳐진다
C++이라면 매크로 자체를 줄이는 편이 좋다. 다만 “식을 소스에 적힌 그대로 문자열로 남기는” 일만큼은 매크로가 아니면 할 수 없다. C++20부터는 std::source_location으로 파일/줄/함수명은 매크로 없이 얻을 수 있다.
댓글 남기기