C 전처리로 잠시 루프를 쓰는 방법?
교육적/해킹적 관점에서 이 질문을 하는 것이다, (이런 코드는 별로 하고 싶지 않다.)
C 전처리기 지시문을 사용해서만 swid loop 구현이 가능한가?매크로는 재귀적으로 확장할 수 없는 것으로 알고 있는데, 어떻게 이런 일이 성사될까?
잠시 루프를 구현하려면 전처리에 재귀 기능을 사용해야 한다.재귀하는 가장 쉬운 방법은 지연된 표현을 사용하는 것이다.지연 표현식은 완전히 확장하기 위해 더 많은 검색이 필요한 표현식:
#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(id) id DEFER(EMPTY)()
#define EXPAND(...) __VA_ARGS__
#define A() 123
A() // Expands to 123
DEFER(A)() // Expands to A () because it requires one more scan to fully expand
EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan
이것이 왜 중요한가?매크로를 스캔하고 확장하면 비활성화 컨텍스트가 생성된다.이러한 비활성화 컨텍스트는 현재 확장되고 있는 매크로를 가리키는 토큰을 파란색으로 칠하게 할 것이다.따라서 일단 파란색으로 칠해진 매크로는 더 이상 확장되지 않을 것이다.매크로가 재귀적으로 확장되지 않는 이유다.그러나 비활성화 컨텍스트는 한 번의 스캔에서만 존재하므로 확장을 연기함으로써 매크로가 파란색으로 칠해지는 것을 방지할 수 있다.우리는 단지 그 표현에 더 많은 스캔을 적용하면 될 것이다.이걸로 할 수 있어.EVAL
매크로:
#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 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))
이제 이 모든 매크로들을 가지고 우리는 재귀적인 글을 쓸 수 있다.WHILE
. 우리는 a를 사용한다.WHILE_INDIRECT
매크로(macro)를 다시 반복적으로 참조한다.이렇게 하면 매크로가 다른 스캔(및 다른 비활성화 컨텍스트를 사용)에서 확장되기 때문에 매크로가 파란색으로 칠해지는 것을 방지할 수 있다.그WHILE
매크로에는 술어 매크로, 연산자 매크로 및 상태(변수 인수).그것은 술어 매크로가 false(즉 0)를 반환할 때까지 이 연산자 매크로를 상태에 계속 적용한다.
#define WHILE(pred, op, ...) \
IF(pred(__VA_ARGS__)) \
( \
OBSTRUCT(WHILE_INDIRECT) () \
( \
pred, op, op(__VA_ARGS__) \
), \
__VA_ARGS__ \
)
#define WHILE_INDIRECT() WHILE
실증적 목적을 위해 우리는 단지 인수의 수가 1일 때 확인하는 술어를 만들려고 한다.
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define IS_1(x) CHECK(PRIMITIVE_CAT(IS_1_, x))
#define IS_1_1 ~, 1,
#define PRED(x, ...) COMPL(IS_1(NARGS(__VA_ARGS__)))
다음으로 교환원을 만들면 두 개의 토큰을 연결시킬 겁니다. 日本語)도 만든다.M
최종 출력을 처리할 ):
#define OP(x, y, ...) CAT(x, y), __VA_ARGS__
#define M(...) CAT(__VA_ARGS__)
그리고 나서 사용WHILE
매크로:
M(EVAL(WHILE(PRED, OP, x, y, z))) //Expands to xyz
물론, 어떤 종류의 술어나 운영자는 그것에 넘겨질 수 있다.
전처리에 루프를 쓸 수 있는 Boost 전처리기 라이브러리를 살펴보십시오.
이런 목적으로 메타템플릿 프로그래밍을 이용하는데, 일단 익숙해지면 재미있어.그리고 신중히 사용할 때 매우 유용하다.왜냐하면 앞서 언급한 바와 같이, 컴파일러가 무한 루프 또는 스택 오버플로우를 일으킬 수 있을 정도로 튜닝이 완벽하기 때문이다!당신의 컴파일이 30기가바이트 이상의 메모리와 모든 CPU를 당신의 무한 루프 코드를 컴파일하는 것을 찾기 위해 약간의 커피를 얻는 것만큼 좋은 것은 없다!
글쎄, 잠깐 루프라는 것이 아니라 카운터 루프라는 것, 그럼에도 불구하고 루프는 깨끗한 CPP(템플릿과 C++ 없음)에서 가능하다.
#ifdef pad_always
#define pad(p,f) p##0
#else
#define pad0(p,not_used) p
#define pad1(p,not_used) p##0
#define pad(p,f) pad##f(p,)
#endif
// f - padding flag
// p - prefix so far
// a,b,c - digits
// x - action to invoke
#define n0(p,x)
#define n1(p,x) x(p##1)
#define n2(p,x) n1(p,x) x(p##2)
#define n3(p,x) n2(p,x) x(p##3)
#define n4(p,x) n3(p,x) x(p##4)
#define n5(p,x) n4(p,x) x(p##5)
#define n6(p,x) n5(p,x) x(p##6)
#define n7(p,x) n6(p,x) x(p##7)
#define n8(p,x) n7(p,x) x(p##8)
#define n9(p,x) n8(p,x) x(p##9)
#define n00(f,p,a,x) n##a(pad(p,f),x)
#define n10(f,p,a,x) n00(f,p,9,x) x(p##10) n##a(p##1,x)
#define n20(f,p,a,x) n10(f,p,9,x) x(p##20) n##a(p##2,x)
#define n30(f,p,a,x) n20(f,p,9,x) x(p##30) n##a(p##3,x)
#define n40(f,p,a,x) n30(f,p,9,x) x(p##40) n##a(p##4,x)
#define n50(f,p,a,x) n40(f,p,9,x) x(p##50) n##a(p##5,x)
#define n60(f,p,a,x) n50(f,p,9,x) x(p##60) n##a(p##6,x)
#define n70(f,p,a,x) n60(f,p,9,x) x(p##70) n##a(p##7,x)
#define n80(f,p,a,x) n70(f,p,9,x) x(p##80) n##a(p##8,x)
#define n90(f,p,a,x) n80(f,p,9,x) x(p##90) n##a(p##9,x)
#define n000(f,p,a,b,x) n##a##0(f,pad(p,f),b,x)
#define n100(f,p,a,b,x) n000(f,p,9,9,x) x(p##100) n##a##0(1,p##1,b,x)
#define n200(f,p,a,b,x) n100(f,p,9,9,x) x(p##200) n##a##0(1,p##2,b,x)
#define n300(f,p,a,b,x) n200(f,p,9,9,x) x(p##300) n##a##0(1,p##3,b,x)
#define n400(f,p,a,b,x) n300(f,p,9,9,x) x(p##400) n##a##0(1,p##4,b,x)
#define n500(f,p,a,b,x) n400(f,p,9,9,x) x(p##500) n##a##0(1,p##5,b,x)
#define n600(f,p,a,b,x) n500(f,p,9,9,x) x(p##600) n##a##0(1,p##6,b,x)
#define n700(f,p,a,b,x) n600(f,p,9,9,x) x(p##700) n##a##0(1,p##7,b,x)
#define n800(f,p,a,b,x) n700(f,p,9,9,x) x(p##800) n##a##0(1,p##8,b,x)
#define n900(f,p,a,b,x) n800(f,p,9,9,x) x(p##900) n##a##0(1,p##9,b,x)
#define n0000(f,p,a,b,c,x) n##a##00(f,pad(p,f),b,c,x)
#define n1000(f,p,a,b,c,x) n0000(f,p,9,9,9,x) x(p##1000) n##a##00(1,p##1,b,c,x)
#define n2000(f,p,a,b,c,x) n1000(f,p,9,9,9,x) x(p##2000) n##a##00(1,p##2,b,c,x)
#define n3000(f,p,a,b,c,x) n2000(f,p,9,9,9,x) x(p##3000) n##a##00(1,p##3,b,c,x)
#define n4000(f,p,a,b,c,x) n3000(f,p,9,9,9,x) x(p##4000) n##a##00(1,p##4,b,c,x)
#define n5000(f,p,a,b,c,x) n4000(f,p,9,9,9,x) x(p##5000) n##a##00(1,p##5,b,c,x)
#define n6000(f,p,a,b,c,x) n5000(f,p,9,9,9,x) x(p##6000) n##a##00(1,p##6,b,c,x)
#define n7000(f,p,a,b,c,x) n6000(f,p,9,9,9,x) x(p##7000) n##a##00(1,p##7,b,c,x)
#define n8000(f,p,a,b,c,x) n7000(f,p,9,9,9,x) x(p##8000) n##a##00(1,p##8,b,c,x)
#define n9000(f,p,a,b,c,x) n8000(f,p,9,9,9,x) x(p##9000) n##a##00(1,p##9,b,c,x)
#define n00000(f,p,a,b,c,d,x) n##a##000(f,pad(p,f),b,c,d,x)
#define n10000(f,p,a,b,c,d,x) n00000(f,p,9,9,9,9,x) x(p##10000) n##a##000(1,p##1,b,c,d,x)
#define n20000(f,p,a,b,c,d,x) n10000(f,p,9,9,9,9,x) x(p##20000) n##a##000(1,p##2,b,c,d,x)
#define n30000(f,p,a,b,c,d,x) n20000(f,p,9,9,9,9,x) x(p##30000) n##a##000(1,p##3,b,c,d,x)
#define n40000(f,p,a,b,c,d,x) n30000(f,p,9,9,9,9,x) x(p##40000) n##a##000(1,p##4,b,c,d,x)
#define n50000(f,p,a,b,c,d,x) n40000(f,p,9,9,9,9,x) x(p##50000) n##a##000(1,p##5,b,c,d,x)
#define n60000(f,p,a,b,c,d,x) n50000(f,p,9,9,9,9,x) x(p##60000) n##a##000(1,p##6,b,c,d,x)
#define n70000(f,p,a,b,c,d,x) n60000(f,p,9,9,9,9,x) x(p##70000) n##a##000(1,p##7,b,c,d,x)
#define n80000(f,p,a,b,c,d,x) n70000(f,p,9,9,9,9,x) x(p##80000) n##a##000(1,p##8,b,c,d,x)
#define n90000(f,p,a,b,c,d,x) n80000(f,p,9,9,9,9,x) x(p##90000) n##a##000(1,p##9,b,c,d,x)
#define cycle5(c1,c2,c3,c4,c5,x) n##c1##0000(0,,c2,c3,c4,c5,x)
#define cycle4(c1,c2,c3,c4,x) n##c1##000(0,,c2,c3,c4,x)
#define cycle3(c1,c2,c3,x) n##c1##00(0,,c2,c3,x)
#define cycle2(c1,c2,x) n##c1##0(0,,c2,x)
#define cycle1(c1,x) n##c1(,x)
#define concat(a,b,c) a##b##c
#define ck(arg) a[concat(,arg,-1)]++;
#define SIZEOF(x) (sizeof(x) / sizeof((x)[0]))
void check5(void)
{
int i, a[32769];
for (i = 0; i < SIZEOF(a); i++) a[i]=0;
cycle5(3,2,7,6,9,ck);
for (i = 0; i < SIZEOF(a); i++) if (a[i] != 1) printf("5: [%d] = %d\n", i+1, a[i]);
}
여기에 합법적으로 그것을 완수할 수 있는 규칙들의 남용들이 있다.C 전처리기사를 직접 작성하십시오.네가 원하는 대로 #프라그마 지시문을 해석하도록 해.
재귀 포함 파일을 사용하는 경우.유감스럽게도 전처리가 허용하는 최대 깊이 이상으로 루프를 반복할 수는 없다.
C++ 템플릿은 튜링 완료로 유사한 방식으로 사용할 수 있는 것으로 나타났다.생성 프로그래밍 체크아웃
컴파일러가 짜증을 내고 어떤 루프를 풀지 않았을 때 이 계획이 유용하다는 것을 알았다.
#repeat20(x) {x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;} 정의
REFT20(val = pleaseconverge(val) )
하지만 IMHO, 만약 당신이 그것보다 훨씬 더 복잡한 것이 필요하다면, 당신은 당신만의 프리프로세서를 써야 한다.예를 들어, 사전 프로세서가 적합한 헤더 파일을 생성할 수 있으며, 이 단계를 Makefile에 포함시켜 하나의 명령으로 모든 것을 원활하게 컴파일할 수 있다.내가 해치웠어.
참조URL: https://stackoverflow.com/questions/319328/how-to-write-a-while-loop-with-the-c-preprocessor
'IT이야기' 카테고리의 다른 글
정의되지 않은 지정되지 않은 구현 정의 동작 (0) | 2022.05.25 |
---|---|
Vue.js - 프롭 정의되지 않음 (0) | 2022.05.25 |
Prety를 사용하여 요소 태그에서 특성을 구분하지 않는 방법 (0) | 2022.05.25 |
v-data-table 바닥글에서 페이지당 텍스트 행 수 설정 (0) | 2022.05.25 |
Firebase 인증 상태가 변경된 후 Vue 앱 초기화 (0) | 2022.05.25 |