C 프리프로세서의 Variadic 매크로
Variadic macro in the C preprocessor가변 매크로란 일부 컴퓨터 프로그래밍 언어, 특히 C 프리프로세서의 기능으로, 매크로가 다양한 수의 인수를 받아들이도록 선언될 수 있습니다.
변수 인수 매크로는 1999년 C 언어 표준의 ISO/IEC 9899:1999(C99) 개정판 및 2011년 C++ 언어 [1]표준의 ISO/IEC 14882:2011(C++11) 개정판에서 도입되었다.C++20 [2]에서는 인수를 지정하지 않는 바리에딕 매크로의 지원이 추가되었습니다.
선언 구문
선언 구문은 가변 함수의 구문과 유사합니다: 3개의 완전 정지 "의 시퀀스입니다...." 는 하나 이상의 인수를 전달해야 함을 나타내기 위해 사용됩니다.매크로 확장 중 특수 식별자가 발생할 때마다__VA_ARGS__전달된 인수로 대체됩니다.
또한 일반 매크로 인수는 다음 명령어 앞에 나열될 수 있습니다....
단, 정규 인수는 다음에 나열되지 않을 수 있습니다.[3]...
.
변수 인수 목록의 개별 인수에 액세스하거나 전달된 수를 확인하는 방법은 제공되지 않습니다.그러나 매크로를 작성하여 [4]전달된 인수 수를 셀 수 있습니다.
C99 규격과 C++11 규격 모두 적어도1개의 인수가 필요하지만 C++20 이후로는 이 제한이 해제되었습니다.__VA_OPT__기능 매크로그__VA_OPT__매크로가 인수가 있는 경우 해당 인수로 대체되며, 그렇지 않은 경우 생략됩니다.그러나 [3][5]공통 컴파일러에서는 이 추가 전에 제로 인수를 전달할 수도 있습니다.
C 프리프로세서규칙은 다음 인수에서 매크로 이름을 금지합니다.__VA_OPT__재귀적으로 팽창하는 것을 막습니다.단,[6] 이 제한은 임의의 고정 수의 재귀 확장까지 회피할 수 있습니다.
지지하다
C 및 C++ 코드를 컴파일할 때 변수 인수 매크로를 지원하는 컴파일러는 GNU 컴파일러 컬렉션 3.0,[3] Clang(모든 버전),[7] Visual Studio 2005,[5] C++ Builder 2006 및 Oracle Solaris Studio(이전 Sun Studio)입니다.Forte Developer 6 업데이트 2(C++ 버전 5.3).[8]또한 GCC는 Objective-C를 컴파일할 때 이러한 매크로를 지원합니다.
에 대한 지원__VA_OPT__ 제로 인수를 지원하는 매크로가 GNU 컴파일러 컬렉션 [9]8, Clang [10]6, Visual Studio [11]2019에 추가되었습니다.
예
만약 a가printf
-양함수 dbgprintf()
desired는 인수로 호출된 파일 및 행 번호를 사용합니다.다음 솔루션이 적용됩니다.
// 구현된 기능 무효 리얼 데이터베이스 프린트 (컨스턴트 차 *Source Filename, 인트 소스리네노, 컨스턴트 차 *CFormatString, ...); // C++11의 가변 매크로 지원 제한으로 인해 다음 항목 // 간단한 솔루션은 실패할 수 있으므로 피해야 합니다. // // #dbgprintf(cformat, ...) \ // realdbgprintf (_FILE__, __LINE__, cformat, __VA_)ARGS__) // // 이유는 // // dbgprintf("Hallo") // //로 확장됩니다. // // realdbgprintf (_FILE__, __LINE__, "Hallo", ) // // 여기서 닫힘 괄호 앞의 쉼표로 구문 오류가 발생합니다. // // GNU C++는 이 문제를 해결하기 위해 비포터블 확장을 지원합니다. // // #dbgprintf(cformat, ...) \ // realdbgprintf (_FILE__, __LINE__, cformat, ##_VA_)ARGS__) // // C++20은 최종적으로 다음 구문을 지원합니다. // // #dbgprintf(cformat, ...) \ // realdbgprintf (_FILE__, __LINE__, cformat __VA_OPT_(,) __VA_ARGS__) // // 변수 인수의 일부로 'cformat' 문자열을 사용하면 // 상기의 비호환성을 회피합니다.이게 좀 까다롭긴 한데 // 휴대용. #dbgprintf(...) realdbgprintf(_FILE__, __LINE__, __VA_)를 정의합니다.ARGS__)
dbgprintf()
라고 불릴 수 있다
dbgprintf ("안녕, 세상아");
로 확장됩니다.
리얼 데이터베이스 프린트 (__FILE__, __LINE__, "안녕, 세상아");
또 다른 예는
dbgprintf(%d + %d = %d, 2, 2, 5);
로 확장됩니다.
리얼 데이터베이스 프린트(__FILE__, __LINE__, %d + %d = %d, 2, 2, 5);
가변 매크로를 사용하지 않고 래퍼 쓰기printf
직접 가능하지 않습니다.표준 회피책은 C/C++의 stdargs 기능을 사용하여 함수 호출을 실행하는 것입니다.vprintf
대신.
후행 콤마
C99에서 바리에이딕 매크로용으로 빈 arg를 가진 후행 콤마를 생성하는 경우 이식성 문제가 있습니다.일부 컴파일러(예: 새로운 표준 준거[5] 프리프로세서를 사용하지 않는 경우 Visual Studio)에서는 후행 콤마가 자동으로 제거됩니다.기타 컴파일러(GCC[3] 등)는 퍼팅을 지원합니다.##
앞에__VA_ARGS__.
# MYLOG ( FormatLiteral , ... ) fprintf ( stderr , %s ( %u ) : " FormatLiteral " \n , _FILE _ _ , _ _ LINE _ _ _ , _ _ VA _ )를 정의합니다.ARGS__)
다음 응용 프로그램이 작동합니다.
마이로그("풍선 %u이 너무 많다", 42);
로 확장됩니다.
인쇄 (하드, %s(%u): " "풍선 %u이 너무 많다" "\n", __FILE__, __LINE__, 42);
와 동등하다.
인쇄 (하드, %s(%u): 풍선 %u이(가) 너무 많습니다.\n", __FILE__, __LINE__, 42);
이 어플리케이션을 보세요.
마이로그("차렷!");
로 확장됩니다.
인쇄 (하드, %s(%u): " "차렷!" "\n", __FILE__, __LINE__, );
GCC에서 구문 오류가 생성됩니다.
GCC는, 다음의(포터블이 아닌) 내선 번호를 서포트합니다.
# MYLOG ( FormatLiteral , ... ) fprintf ( stderr , %s ( %u ) : " FormatLiteral " \n , _FILE _ _ , _ _ LINE _ _ _ _ , # _ _ VA _ )를 정의합니다.ARGS__)
이 명령어는 다음과 같은 경우에 후행 쉼표는__VA_ARGS__비어 있습니다.
대체 수단
C99에 변수 인수가 존재하기 전에는 이중 네스트 괄호를 사용하여 에 공급될 수 있는 변수 수를 이용하는 것이 매우 일반적이었습니다.printf()
기능:
#dbgprintf(x) realdbgprintf x의 번호
dbgprintf()
그러면 다음과 같이 호출할 수 있습니다.
dbgprintf (("안녕하세요, %d월드", 27));
다음과 같이 확장됩니다.
리얼 데이터베이스 프린트 ("안녕하세요, %d월드", 27);
레퍼런스
- ^ C99 프리프로세서 동기화 초안 변경 작업– http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm
- ^ "Comma omission and comma deletion". July 12, 2017. Retrieved June 14, 2018.
- ^ a b c d Variadic 매크로– GNU 컴파일러 컬렉션(GCC) 사용
- ^ Laurent Deniau (2006-01-16). "__VA_NARG__". Newsgroup: comp.std.c. Usenet: [email protected].
- ^ a b c 가변 매크로 (C++)
- ^ C++20 __VA_OPT__를 사용한 재귀 매크로
- ^ __VA_를 언급하는 Clang 소스 코드 변경ARGS__ 지원(2006-07-29).Clang은 2007년에 오픈소싱되었습니다.http://llvm.org/viewvc/llvm-project?view=revision&revision=38770
- ^ Sun Studio 기능 비교– http://developers.sun.com/sunstudio/support/CCcompare.html
- ^ "C++2a Support in GCC". Retrieved June 14, 2018.
- ^ "C++ Support in Clang". Retrieved June 14, 2018.
- ^ "MSVC new preprocessor overview". September 10, 2020. Retrieved December 8, 2020.