재귀 매크로를 사용할 수 있습니까?
C/C++에서 재귀 매크로를 사용할 수 있는지 알고 싶습니다.예인 경우 예를 제시해 주세요.
두 번째: 아래 코드를 실행할 수 없는 이유는 무엇입니까?내가 뭘 잘못하고 있는 거지?재귀 매크로 때문인가요?
# define pr(n) ((n==1)? 1 : pr(n-1))
void main ()
{
int a=5;
cout<<"result: "<< pr(5) <<endl;
getch();
}
매크로가 재귀적으로 직접 확장되는 것은 아니지만 회피책이 있습니다.가 「」를 해 .pr(5):
pr(5)
^
콘텍스트가 에, 「」를 하면,pr 추가:
((5==1)? 1 : pr(5-1))
^
그것은 파란색으로 칠해져 우리가 무엇을 시도해도 더 이상 확장될 수 없다.그러나 지연 표현과 일부 간접 표현을 사용하면 매크로가 파란색으로 칠해지는 것을 방지할 수 있습니다.
# define EMPTY(...)
# define DEFER(...) __VA_ARGS__ EMPTY()
# define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
# define EXPAND(...) __VA_ARGS__
# define pr_id() pr
# define pr(n) ((n==1)? 1 : DEFER(pr_id)()(n-1))
이제 다음과 같이 확장됩니다.
pr(5) // Expands to ((5==1)? 1 : pr_id ()(5 -1))
완벽해, 왜냐면pr하면 더 수 .스캔을 더 확장하려면 다른 스캔을 적용하기만 하면 됩니다.
EXPAND(pr(5)) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : pr_id ()(5 -1 -1)))
다음 두 가지 스캔을 적용하여 더 확장할 수 있습니다.
EXPAND(EXPAND(pr(5))) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : ((5 -1 -1==1)? 1 : pr_id ()(5 -1 -1 -1))))
그러나 종료 조건이 없기 때문에 충분한 스캔을 적용할 수 없습니다.무엇을 달성하고 싶은지는 잘 모르겠습니다만, 재귀 매크로를 작성하는 방법이 궁금하다면, 재귀 반복 매크로를 작성하는 방법의 예를 다음에 제시하겠습니다.
먼저 많은 스캔을 적용할 매크로:
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__
다음으로 패턴 매칭에 도움이 되는 콘캣 매크로:
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
증분 및 감소 카운터:
#define INC(x) PRIMITIVE_CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_9 9
#define DEC(x) PRIMITIVE_CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
조건에 유용한 매크로:
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)
이 모든 것을 종합하면, 반복 매크로를 작성할 수 있습니다.
#define REPEAT(count, macro, ...) \
WHEN(count) \
( \
OBSTRUCT(REPEAT_INDIRECT) () \
( \
DEC(count), macro, __VA_ARGS__ \
) \
OBSTRUCT(macro) \
( \
DEC(count), __VA_ARGS__ \
) \
)
#define REPEAT_INDIRECT() REPEAT
//An example of using this macro
#define M(i, _) i
EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7
따라서 일부 회피책에서는 C/C++에 재귀 매크로가 있을 수 있습니다.
컴파일러는 실제 컴파일이 아닌 전처리만 할 수 있는 옵션을 제공합니다.이것은 매크로에서 문제를 찾으려는 경우에 유용합니다.를 들어, 「」를 사용합니다.g++ -E:
> g++ -E recursiveMacro.c
# 1 "recursiveMacro.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "recursiveMacro.c"
void main ()
{
int a=5;
cout<<"result: "<< ((5==1)? 1 : pr(5 -1)) <<endl;
getch();
}
보시다시피 재귀적이지 않습니다. pr(x)는 전처리 중에 한 번만 교체됩니다.가 하는 텍스트 스트링으로 이은 실제로 그것은 실제로 다음과 같은 표현을 평가하지 않습니다.(x == 1).
는 '코드가 컴파일되지 않기 때문입니다.pr(5 -1)는 프리패널로 대체되지 않았기 때문에, 미정의의 함수에의 콜로서 송신원에 보내집니다.
C 또는 C++에는 재귀 매크로가 없어야 합니다.
C++ 표준 섹션 16.3.4 단락 2의 관련 언어:
이 대체 목록 검사 중에 대체되는 매크로의 이름이 발견되면(원본 파일의 나머지 전처리 토큰은 제외) 대체되지 않습니다.게다가 네스트 된 치환에 의해서 치환되는 매크로의 이름이 발견되었을 경우, 치환되지 않습니다.이러한 대체되지 않은 매크로 이름 전처리 토큰은 나중에 해당 매크로 이름 전처리 토큰이 대체되었을 수 있는 컨텍스트에서 다시 검사(재검사)되더라도 더 이상 대체할 수 없습니다.
이 언어에는 약간의 흔들림이 있다.서로 호출하는 여러 매크로를 사용하는 경우, 그 표현으로 무엇을 해야 하는지 잘 알 수 없는 회색 영역이 있습니다.이 언어 변호사의 문제에 관한 C++ 규격에 반하는 활발한 문제가 있습니다.http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268 를 참조해 주세요.
모든 컴파일러 벤더는 이 언어 변호사의 문제를 무시하고 그 의도를 이해하고 있습니다.
C 또는 C++에서는 재귀 매크로를 사용할 수 없습니다.
컴파일을 할 수 없기 때문에 실행할 수 없는 경우가 대부분입니다.또한 올바르게 컴파일되면 항상 1이 반환됩니다.말인가요?(n==1)? 1 : n * pr(n-1).
매크로는 재귀적일 수 없습니다. Astari)에 따르면 목록에 있는 매크로가 남아 16.3.4.2(「다」)가 됩니다.pr
이 교체 목록 검사 중에 교체 중인 매크로의 이름이 발견되면(소스 파일의 나머지 사전 처리 토큰은 제외) 교체되지 않습니다.또한 네스트된 치환에서 치환되는 매크로의 이름이 발견되어도 치환되지 않습니다.이러한 대체되지 않은 매크로 이름 전처리 토큰은 나중에 해당 매크로 이름 전처리 토큰이 대체되었을 수 있는 컨텍스트에서 다시 검사(재검사)되더라도 더 이상 대체할 수 없습니다.
문의처:
cout<<"result: "<< pr(5) <<endl;
프리프로세서에 의해 다음과 같이 변환되었습니다.
cout<<"result: "<< (5==1)? 1 : pr(5-1) <<endl;
때, 「 」의 정의는 과 같습니다.pr"lost는 "scope (같은 는 macro lost.라는 이름의 때문입니다.또한 "pr"은 이 범위(fact)에서 선언되지 않았기 때문입니다.이는 이름이 붙은 함수가 없기 때문입니다.pr.
C++ 에서는 매크로의 사용을 권장하지 않습니다.그냥 함수를 써보는 게 어때?
이 경우 템플릿 함수를 작성하여 컴파일 시 해결되며 상수 값으로 동작합니다.
template <int n>
int pr() { pr<n-1>(); }
template <>
int pr<1>() { return 1; }
C 또는 C++에는 재귀 매크로를 사용할 수 없습니다.
언급URL : https://stackoverflow.com/questions/12447557/can-we-have-recursive-macros
'programing' 카테고리의 다른 글
| Vee 동적 입력 행 처리 검증 (0) | 2022.07.30 |
|---|---|
| Mac에서의 JDK 경로란? (0) | 2022.07.30 |
| 어레이 주소 지정 시 다른 포인터 연산 결과 (0) | 2022.07.29 |
| Vue 데이터 모델 속성 기반 속성 이름의 값을 가져오시겠습니까? (0) | 2022.07.29 |
| 부팅에 실패했습니다.이진수를 찾을 수 없습니다.이클립스 헬리오스의 CDT (0) | 2022.07.29 |