Replacing text macros
전처리기는 텍스트 매크로 치환을 지원합니다. 함수 형태의 텍스트 매크로 치환도 지원됩니다.
목차구문
설명
#define 지시문#define 지시문은 identifier 를 매크로로 정의하며, 이는 컴파일러에게 identifier 의 대부분의 연속적인 발생을 추가로 처리될 replacement-list 로 대체하도록 지시합니다. 예외는 스캐닝 및 대체 규칙 에서 발생합니다. 식별자가 이미 어떤 유형의 매크로로 정의되어 있는 경우, 정의가 동일하지 않으면 프로그램은 잘못된 형식입니다. 객체형 매크로객체형 매크로는 정의된 identifier 의 모든 발생을 replacement-list 로 대체합니다. #define 지시자의 버전 (1)은 정확히 이런 방식으로 동작합니다. 함수형 매크로함수형 매크로는 정의된 identifier 의 각 발생을 replacement-list 로 대체하며, 추가적으로 여러 인수를 취하여 replacement-list 내의 parameters 중 해당하는 발생을 대체합니다. 함수형 매크로 호출의 구문은 함수 호출의 구문과 유사합니다: 매크로 이름의 각 인스턴스 뒤에 ( 가 다음 전처리 토큰으로 오는 경우, 이는 replacement-list 로 대체되는 토큰 시퀀스를 시작합니다. 이 시퀀스는 일치하는 ) 토큰에 의해 종료되며, 중간에 있는 일치하는 왼쪽 및 오른쪽 괄호 쌍은 건너뜁니다.
버전 (2)의 경우, 인수의 개수가 매크로 정의의 매개변수 개수와 동일해야 합니다. 버전 (3,4)의 경우, 인수의 개수가 매개변수 개수보다 적어서는 안 됩니다 (
not
(since C++20)
counting
버전 (2)의 #define 지시자는 단순한 함수형 매크로를 정의합니다.
지시문의 버전 (3)은
#define
가변 인자를 갖는 함수형 매크로를 정의합니다. 추가 인자들(
가변 인자
)은
지시문의 버전 (4)는
#define
함수형 매크로를 가변 인자 개수로 정의하지만, 일반 인자는 없습니다. 인자들(
가변 인자
라고 함)은
참고: 함수형 매크로의 인수에 일치하는 왼쪽 및 오른쪽 괄호 쌍으로 보호되지 않은 쉼표가 포함된 경우(가장 일반적으로 템플릿 인수 목록에서 발견됨, 예를 들어 assert ( std:: is_same_v < int , int > ) ; 또는 BOOST_FOREACH ( std:: pair < int , int > p, m ) ), 해당 쉼표는 매크로 인수 구분자로 해석되어 인수 개수 불일치로 인한 컴파일 오류가 발생합니다. 스캐닝 및 교체
참고로, 유사 재귀 매크로를 정의하는 것이 가능합니다:
이 코드 실행
#define EMPTY #define SCAN(x) x #define EXAMPLE_() EXAMPLE #define EXAMPLE(n) EXAMPLE_ EMPTY()(n-1) (n) EXAMPLE(5) SCAN(EXAMPLE(5)) 출력: EXAMPLE_ ()(5 -1) (5) EXAMPLE_ ()(5 -1 -1) (5 -1) (5) 예약된 매크로 이름표준 라이브러리 헤더를 포함하는 번역 단위 는 #define 또는 #undef 를 사용하여 표준 라이브러리 헤더 에 선언된 이름들을 재정의하거나 해제해서는 안 됩니다. 표준 라이브러리의 어떤 부분을 사용하는 번역 단위는 다음과 어휘적으로 동일한 이름을 #define 또는 #undef 하는 것이 허용되지 않습니다:
그렇지 않으면, 동작은 정의되지 않습니다.
# 및 ## 연산자함수형 매크로에서, # 연산자가 replacement-list 내의 식별자 앞에 위치하면, 해당 식별자를 매개변수 치환 과정에 통과시킨 후 결과를 따옴표로 감싸서 문자열 리터럴을 효과적으로 생성합니다. 추가로, 전처리기는 포함된 문자열 리터럴 주변의 따옴표를 이스케이프하기 위해 백슬래시를 추가하고, 필요한 경우 문자열 내부의 백슬래시를 두 배로 늘립니다. 모든 앞뒤 공백은 제거되며, 텍스트 중간의 공백 시퀀스(그러나 포함된 문자열 리터럴 내부는 제외)는 단일 공백으로 축소됩니다. 이 연산을 "stringification"이라고 합니다. Stringification의 결과가 유효한 문자열 리터럴이 아닌 경우, 동작은 정의되지 않습니다.
##
연산자는
replacement-list
내에서 연속된 두 식별자 사이에 위치할 때, 두 식별자(먼저 매크로 확장되지 않음)에 대해 매개변수 치환을 수행한 후 결과를 연결합니다. 이 연산을 "토큰 접합" 또는 "토큰 붙여넣기"라고 합니다. 함께 유효한 토큰을 형성하는 토큰만 접합할 수 있습니다: 더 긴 식별자를 형성하는 식별자, 숫자를 형성하는 숫자, 또는
참고: 일부 컴파일러는 쉼표 다음과
#undef 지시문#undef 지시자는 식별자 를 정의 해제합니다. 즉, #define 지시자에 의한 식별자 의 이전 정의를 취소합니다. 만약 해당 식별자에 연결된 매크로가 없는 경우, 이 지시자는 무시됩니다. 미리 정의된 매크로다음 매크로 이름은 모든 번역 단위에서 미리 정의됩니다:
다음 추가 매크로 이름은 구현에 의해 미리 정의될 수 있습니다:
이러한 매크로의 값은 (
예제
이 코드 실행
#include <iostream> // 함수 팩토리 생성 및 사용 #define FUNCTION(name, a) int fun_##name() { return a; } FUNCTION(abcd, 12) FUNCTION(fff, 2) FUNCTION(qqq, 23) #undef FUNCTION #define FUNCTION 34 #define OUTPUT(a) std::cout << "output: " #a << '\n' // 이후 매크로 정의에서 매크로 사용 #define WORD "Hello " #define OUTER(...) WORD #__VA_ARGS__ int main() { std::cout << "abcd: " << fun_abcd() << '\n'; std::cout << "fff: " << fun_fff() << '\n'; std::cout << "qqq: " << fun_qqq() << '\n'; std::cout << FUNCTION << '\n'; OUTPUT(million); //따옴표가 없는 것에 주목 std::cout << OUTER(World) << '\n'; std::cout << OUTER(WORD World) << '\n'; } 출력: abcd: 12 fff: 2 qqq: 23 34 output: million Hello World Hello WORD World 결함 보고서다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
참고 항목
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||