C 전처리기 연결이 #정의 바깥쪽에 있음
왜 우리가 토큰 연결을 외부에서 사용할 수 없는지 궁금했습니다.define
s.
이것은 제가 이것들을 동시에 원할 때 나타납니다.
- 라이브러리의 충돌 없는 이름 지정(또는 "일반"의 경우)
- 가능성; 때;
define
전체 입니다가 .define
사용되었습니다.
어떤 사람들은 예를 원할 수도 있습니다(실제 질문은 그 아래에 있습니다).
lib.inc:
#ifndef NAME
#error includer should first define NAME
#endif
void NAME() { // works
}
// void NAME##Init() { // doesn't work
// }
main.c:
#define NAME conflictfree
#include "lib.inc"
int main(void) {
conflictfree();
// conflictfreeInit();
return 0;
}
오류:
In file included from main.c:2:0:
lib.h:6:10: error: stray '##' in program
void NAME##Init();
^
경험칙은 "정의 안에 있는 cat only in defin"입니다.그리고 내 기억이 맞다면,그 이유는 전처리 단계 때문입니다.질문:.왜 안 되는 거지?위상-논쟁은 한 때 (논리적인 이유가 아니라) 구현 제한이었던 것처럼 들립니다. 그 후 표준에 도달했습니다.수용하는 것이 무엇이 그렇게 어려운가요?NAME##Init()
한다면NAME()
잘 됩니까?
왜 그것은 쉬운 질문이 아니었습니다.이제는 표준 위원회에 왜 표준화만큼 미쳤는지 물어볼 때가 된 것 같습니다. (지금은 삭제되었습니다.)gets()
기능도 합니까?
가끔, 우리가 원하든 원하지 않든 간에, 그 기준은 단순히 뇌사 상태입니다.첫번째 C는 오늘의 C가 아니었습니다.그것은 오늘날의 C가 되도록 "설계"된 것이 아니라, 그것에 "성장"한 것입니다.이로 인해 도로 위에 많은 불일치와 디자인 결함이 발생했습니다.입니다를 입니다.##
지시선이 아닌 선에서, 하지만 역시 C는 건설된 것이 아니라 성장된 것입니다.
어쨌든 우리는 기준을 미화하기 위해 여기에 온 것이 아니기 때문에 이를 극복하기 위한 한 가지 방법은 다음과 같습니다.lib.inc
...
#include <stdio.h>
#ifndef NAME
#error Includer should first define 'NAME'!
#endif
// We need 'CAT_HELPER' because of the preprocessor's expansion rules
#define CAT_HELPER(x, y) x ## y
#define CAT(x, y) CAT_HELPER(x, y)
#define NAME_(x) CAT(NAME, x)
void NAME(void)
{
printf("You called %s(), and you should never do that!\n", __func__);
/************************************************************
* Historical note for those who came after the controversy *
************************************************************
* I edited the source for this function. It's 100% safe now.
* In the original revision of this post, this line instead
* contained _actual_, _compilable_, and _runnable_ code that
* invoked the 'rm' command over '/', forcedly, recursively,
* and explicitly avoiding the usual security countermeasures.
* All of this under the effects of 'sudo'. It was a _bad_ idea,
* but hopefully I didn't actually harm anyone. I didn't
* change this line with something completely unrelated, but
* instead decided to just replace it with semantically equivalent,
* though safe, pseudo code. I never had malicious intentions.
*/
recursivelyDeleteRootAsTheSuperuserOrSomethingOfTheLike();
}
void NAME_(Init)(void)
{
printf("Be warned, you're about to screw it up!\n");
}
에서.main.c
...
#define NAME NeverRunThis
#include "lib.inc"
int main() {
NeverRunThisInit();
NeverRunThis();
return 0;
}
근거"의에서, "ANSIC " 3.8.3.3 를 합니다.##
연산자가 설명됩니다.기본 원칙 중 하나는 다음과 같습니다.
##에 대한 피연산자로서의 공식 매개변수(또는 정상 피연산자)는 붙여넣기 전에 확장되지 않습니다.
이는 다음을 얻을 수 있음을 의미합니다.
#define NAME foo
void NAME##init(); // yields "NAMEinit", not "fooinit"
이 때문에 이런 맥락에서는 오히려 쓸모가 없어지며, 매크로에 저장된 것을 연결하기 위해 두 개의 매크로 계층을 사용해야 하는 이유를 설명합니다.이 아닐 왜냐하면 는 (이 예에서는 명시적 다수 입니다. 왜냐하면 이제 (이 예에서는) 명시적 문자열과도 연결할 수 없기 때문입니다."NAME
" 원하는 경우 항상 매크로 값으로 먼저 확장됩니다.
C 언어의 많은 부분이 표준화 이전에 진화하고 발전한 반면,##
C89 위원회에 의해 발명되었기 때문에, 실제로 그들은 다른 접근법을 사용하기로 결정할 수도 있었습니다.저는 심령술사가 아니기 때문에 C89 표준 위원회가 토큰 붙여넣기를 정확히 어떻게 표준화하기로 결정했는지 알 수 없지만, ANSIC 이론적 근거 3.8.3.3은 "그 설계 원리는 선행 기술의 본질적인 특징을 암호화하고 문자열화 연산자의 사양과 일치합니다."라고 명시하고 있습니다.
기준을 이 되도록 하는 것.X ## Y
매크로 본체 외부에서 허용되는 경우에는 다음과 같은 경우에도 크게 도움이 되지 않습니다.X
아니면Y
입니다 이전에는 되지 않았을##
되므로, 수 있다고 말입니다.NAME ## Init
것,론의 인 매크로를 갖게 .##
바꿔야만 할 겁니다 바뀌지 , 여전히인 방법이 할 것입니다.의미론이 바뀌지 않았다면, 당신은 여전히 방향 전환이 필요할 것입니다.그리고 그 방향성을 얻을 수 있는 유일한 방법은 어쨌든 매크로 바디 내에서 그것을 사용하는 것입니다!
C 전처리기는 이미 사용자가 원하는 작업을 수행할 수 있도록 허용합니다(정확하게는 원하는 구문이 아닌 경우).lib.inc
다음과 같은 추가 매크로를 정의합니다.
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y
#define NAME_(name) CAT(NAME, name)
이 를 .NAME_()
NAME
void NAME_(Init)() {
}
언급URL : https://stackoverflow.com/questions/35925494/c-preprocessor-concatenation-outside-of-define
'source' 카테고리의 다른 글
Gutenberg에 있는 Woocommerce의 블록에 제품 속성 추가 (0) | 2023.09.19 |
---|---|
docker - administrator & mariadb와 함께 compose하여 데이터베이스 연결 시도 시 403을 보여줍니다. (0) | 2023.09.19 |
코드 사인 오류:'iPhone Developer' ID가 기본 키 체인의 유효한 인증서/개인 키 쌍과 일치하지 않습니다. (0) | 2023.09.19 |
Secure C 및 Secure C 관용구 쓰기 (0) | 2023.09.19 |
페이지 로드 시 표현식 표시 안 함 (0) | 2023.09.19 |