## 및 __LINE __ (위치 매크로와 토큰 연결)로 C 매크로 만들기


107

줄 번호에 따라 이름을 가진 함수를 만드는 C 매크로를 만들고 싶습니다. 나는 다음과 같은 일을 할 수 있다고 생각했습니다 (실제 함수는 중괄호 안에 문이있을 것입니다) :

#define UNIQUE static void Unique_##__LINE__(void) {}

나는 다음과 같이 확장되기를 바랐다.

static void Unique_23(void) {}

작동하지 않습니다. 토큰 연결을 사용하면 위치 지정 매크로가 문자 그대로 처리되어 다음으로 확장됩니다.

static void Unique___LINE__(void) {}

이것이 가능합니까?

(예, 아무리 쓸모 없어 보이더라도 이렇게하고 싶은 진짜 이유가 있습니다).


간접 매크로 확장 과 함께 작동하도록 할 수 있다고 생각합니다 .
Ben Stiglitz

4
C 전처리기로 두 번 연결하고 "arg ## _ ## MACRO"에서처럼 매크로를 확장하는 방법의 중복 가능성이 있습니까? 동일 외에 어떤 매크로 간다 __LINE__즉 일반적인 사용 사례이지만 (.
치로 틸리郝海东冠状病六四事件法轮功

답변:


176

문제는 매크로 대체가있을 때 스트링 화 연산자 #나 토큰 붙여 넣기 연산자 ##가 적용 되지 않은 경우에만 전처리 기가 매크로를 재귀 적으로 확장 한다는 것입니다. 따라서 간접적 인 추가 레이어를 사용해야합니다. 토큰 붙여 넣기 연산자를 재귀 적으로 확장 된 인수와 함께 사용할 수 있습니다.

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}

그런 다음, __LINE__확대시 행 번호로 확장됩니다 UNIQUE(이 중 하나에 참여하지 이후 #또는 ##), 다음 토큰 붙여 넣기의 확장시에 발생TOKENPASTE .

또한 같은 줄에 __COUNTER__여러 UNIQUE매크로 인스턴스화가 필요한 경우 평가 될 때마다 새 정수로 확장 되는 매크로 도 있다는 점에 유의 해야합니다 . 참고 : __COUNTER__MS Visual Studio, GCC (V4.3 이후) 및 Clang에서 지원되지만 표준 C는 아닙니다.


3
GNU cpp에서 작동하지 않는 것이 두렵습니다. TOKENPASTE는 LINE 을 리터럴로 사용합니다 . TOKENPASTE (Unique_, LINE )은 Unique___LINE__
DD로

3
@DD : 도우, 이제 고쳐졌습니다. 1이 아닌 2 개의 간접 레이어가 필요합니다.
Adam Rosenfield

__COUNTER__매크로는 GCC에서 나를 위해 작동하지 않았다; __LINE__하나는 광고 된대로 작동 했지만 .
Tyler

2
msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx 에 따르면 COUNTER를 시도하는 모든 사람을위한 추가 정보 는 Microsoft 전용 매크로입니다.
엘바

3
2 단계의 간접이 필요한 이유에 대한 설명이 있습니까? 나는 #과 ##없이 하나만 사용해 보았지만 VS2017에서는 확장되지 않습니다. GCC도 마찬가지입니다. 그러나 두 번째 수준의 간접 참조를 추가하면 확장됩니다. 마법?
Gabe Halsmer 2011

-2

GCC는 결과가 "문자열 화"될 필요가없는 한 "래핑"(또는 실현)을 요구하지 않습니다. Gcc에는 기능이 있지만 모든 것은 일반 C 버전 1로 수행 할 수 있습니다 (일부는 Berkeley 4.3 C가 사용 방법을 배우는 것이 훨씬 더 빠르다고 주장합니다).

** Clang (llvm)은 매크로 확장을 위해 올바른 공백을 사용하지 않습니다. 공백을 추가합니다 (추가 사전 처리를 위해 C 식별자가되는 결과를 확실히 제거함) **, clang은 단순히 # 또는 * 매크로 확장을 수행하지 않습니다. C 전처리 기는 수십 년 동안 예상됩니다. 가장 좋은 예는 X11을 컴파일하는 것입니다. 매크로 "Concat3"이 손상되었습니다. 결과는 이제 MISNAMED C 식별자이며, 물론 빌드에 실패합니다. 그리고 나는 그들의 직업이 실패하기 시작했습니다.

여기에 대한 대답은 "표준을 깨는 새로운 C는 나쁜 C입니다"라고 생각합니다. 이러한 해킹은 항상 (클로버 네임 스페이스) 이유없이 기본값을 변경하지만 실제로 "C를 개선"하지는 않습니다 (자신의 말을 제외하고는 다음과 같습니다. 아직 아무도 책임을지지 않은 모든 파손으로 도망 치는 이유를 설명하기 위해 만들어진 장치입니다).


이전 C 전처리 기가 UNIq _ () __를 지원하지 않았다는 것은 문제가되지 않습니다. 왜냐하면 그들은 "코드의 컴파일러 브랜드 해커가 해커로 표시 될 수 있도록"허용하는 #pragma를 지원하고 또한 표준에 영향을주지 않고 잘 작동합니다. 기본값은 쓸모없는 완탕 파손이며 동일한 이름을 사용하는 동안 함수가 수행하는 작업을 변경하는 것과 마찬가지로 (네임 스페이스 클로버 링) ...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.