programing

이 .c 파일 #에는 왜 포함되어 있습니까?

minecode 2022. 8. 18. 23:05
반응형

이 .c 파일 #에는 왜 포함되어 있습니까?

왜 이렇게 거죠?.c 파일#include 자체 그 자체?

vsimple.c

#define USIZE 8
#include "vsimple.c"
#undef USIZE

#define USIZE 16
#include "vsimple.c"
#undef USIZE

#define USIZE 32
#include "vsimple.c"
#undef USIZE

#define USIZE 64
#include "vsimple.c"
#undef USIZE

에 대해 의 서로 할 수 있습니다.USIZE.

#include지시문은 실제로 에 동봉되어 있습니다.#ifndef재귀가 단일 레벨로 제한됩니다.

#ifndef USIZE

// common definitions
...
//

#define VSENC vsenc
#define VSDEC vsdec

#define USIZE 8
#include "vsimple.c"
#undef USIZE

#define USIZE 16
#include "vsimple.c"
#undef USIZE

#define USIZE 32
#include "vsimple.c"
#undef USIZE

#define USIZE 64
#include "vsimple.c"
#undef USIZE

#else // defined(USIZE)

// macro expanded size specific functions using token pasting

...

#define uint_t TEMPLATE3(uint, USIZE, _t)

unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) {
   ...
}

unsigned char *TEMPLATE2(VSDEC, USIZE)(unsigned char *__restrict ip, size_t n, uint_t *__restrict op) {
   ...
}

#endif

이 모듈에서 정의되어 있는 기능은 다음과 같습니다.

// vsencNN: compress array with n unsigned (NN bits in[n]) values to the buffer out. Return value = end of compressed output buffer out
unsigned char *vsenc8( unsigned char  *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsenc16(unsigned short *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsenc32(unsigned       *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsenc64(uint64_t       *__restrict in, size_t n, unsigned char  *__restrict out);

// vsdecNN: decompress buffer into an array of n unsigned values. Return value = end of compressed input buffer in
unsigned char *vsdec8( unsigned char  *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsdec16(unsigned char  *__restrict in, size_t n, unsigned short *__restrict out);
unsigned char *vsdec32(unsigned char  *__restrict in, size_t n, unsigned       *__restrict out);
unsigned char *vsdec64(unsigned char  *__restrict in, size_t n, uint64_t       *__restrict out);

모두 vsimple.c의 두 가지 함수 정의에서 확장되었습니다.

unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) {
   ...
}

unsigned char *TEMPLATE2(VSDEC, USIZE)(unsigned char *__restrict ip, size_t n, uint_t *__restrict op) {
   ...
}

TEMPLATE2 ★★★★★★★★★★★★★★★★★」TEMPLATE3매크로는 conf.h정의되어 있습니다.

#define TEMPLATE2_(_x_, _y_) _x_##_y_
#define TEMPLATE2(_x_, _y_) TEMPLATE2_(_x_,_y_)

#define TEMPLATE3_(_x_,_y_,_z_) _x_##_y_##_z_
#define TEMPLATE3(_x_,_y_,_z_) TEMPLATE3_(_x_, _y_, _z_)

이러한 매크로는 토큰 붙여넣기를 통해 식별자를 만드는 고전적인 프리프로세서 구조입니다. TEMPLATE2 ★★★★★★★★★★★★★★★★★」TEMPLATE2_으로는 ""라고 불립니다.GLUE ★★★★★★★★★★★★★★★★★」XGLUE.

함수 템플릿은 다음과 같이 시작합니다.

unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) ...

은 첫 됩니다.USIZE8만들다

unsigned char *vsenc8(uint8_t *__restrict in, size_t n, unsigned char *__restrict out) ...

포함, '재귀적 포함'USIZE16을 다음과같이

unsigned char *vsenc16(uint16_t *__restrict in, size_t n, unsigned char *__restrict out) ...

외에 이 「2」를 정의합니다.vsenc32 ★★★★★★★★★★★★★★★★★」vsenc64.

이러한 전처리된 소스 코드의 사용은 개별 파일에 더 많이 사용됩니다.즉, 모든 공통 정의(특히 매크로)를 포함하는 인스턴스화 부분과 다른 매크로 정의로 여러 번 포함된 코드 및 데이터 템플릿용 개별 파일입니다.

QuickJs의 atom 및 opcode 정의에서 enum, string 및 structures 배열을 생성하는 것이 좋은 예입니다.

@chqrlie 100%에 의해 받아들여진 답변이 무슨 일이 일어나고 있는지를 설명해 줍니다.이것은 단지 보충적인 논평일 뿐이다.

를 는, 2 개의 해, C++ 의 모든 할 수 .vsenc8,vsenc16,vsenc32,vsenc64 ★★★★★★★★★★★★★★★★★」vsdec8,vsdec16,vsdec32,vsdec64그러나 반대로 C는 매우 단순한 언어이며 템플릿을 지원하지 않습니다.같은 파워(더 추악한 패키징)를 갖기 위한 일반적인 방법은 언어의 멍청한 매크로 기능을 사용하여 C 프리프로세서가 동등한 작업을 하도록 하는 것입니다.경험이 있는 대부분의 C프로그래머들은 경력 중에 이런 종류의 구조를 반복적으로 접하고 사용하게 될 것입니다.

이 예제를 이해하기 어려운 것은 구현 파일이 처음에 몇 가지 준비 정의를 가지기 위해 통상적으로 5번 구문 분석되고 다음으로 두 함수의 네 가지 변형이 적용된다는 것입니다. 번째 패스)#ifndef USIZE프리프로세서 블록)은 필요한 매크로와 비프로세서 블록이 정의되어 재귀적으로 정의됩니다.#include네 번 다른 방법으로USIZE값(8,16,32,64)을 템플릿 값으로 지정합니다.재귀적으로 포함되는 경우, 대응하는 것은#else프리프로세서 블록은, 다음의 값에 따라서 생성된 2개의 함수의 결과로 해석됩니다.USIZE패스에 사용되는 매크로 상수.

보다 종래의, 개념적으로 명확하고 즉시 이해하기 쉬운 방법은, 예를 들면, 다른 파일로부터 템플릿 기능을 짜넣는 것입니다.vsimple.impl:

#define USIZE 8
/* Generate vsenc8(), vsdec8()... */ 
#include "vsimple.impl"

#undef USIZE
#define USIZE 16
/* Generate vsenc16(), vsdec16()... */ 
#include "vsimple.impl"

#undef USIZE
#define USIZE 32
/* Generate vsenc32(), vsdec32()... */ 
#include "vsimple.impl"

#undef USIZE
#define USIZE 64
/* Generate vsenc64(), vsdec64()... */ 
#include "vsimple.impl"

포함 파일vsimple.c포함된 파일vsimple.impl그 후, 무엇을 언제 정의하고 있는지를 보다 명확하게 정리할 수 있습니다.대부분의 C 프로그래머는 구현 패턴을 인식하고 무슨 일이 일어나고 있는지 즉시 알 수 있습니다.

이러한 방식으로 자신을 재귀적이고 반복적으로 포함시키면 난독화된 C 경기 엔트리에 대한 갈채를 받을 수 있지만 미션 크리티컬 생산 코드에 대한 갈채를 받지 않는 호커스 포주술의 느낌을 불러일으킨다.

그것은 재귀다.여기서 재귀는 C 전처리에 루프가 없기 때문에 편리합니다.또한 여러 개의 파일을 확산시키는 것보다 하나의 파일을 사용하여 트릭을 실행하는 것이 바람직합니다.

1~5의 정수를 템플릿 문자열에 보간하여 표준 출력에 출력하는 함수를 작성해야 한다고 가정합니다.를 들어, 1개의 복사 붙여넣기가 되어 있다고 합니다.printf과 같이 .이치노

void template_print(const char *fmt, int n)
{
   if (n == 0) {
     template_print(fmt, 1);
     template_print(fmt, 2);
     template_print(fmt, 3);
     template_print(fmt, 4);
     template_print(fmt, 5);
   } else {
     /* imagine there are 30 lines of statements here we don't want
        to repeat five times. */
     printf(fmt, n);
   }
}

은, 「이러다」입니다.template_print("whatever %d\n", 0)n파라미터를 지정합니다.

의 은, 0 의 .vsimple.c 없이USIZE정의되어 있습니다.

은 하나의 완결형 함수를 합니다..c"interface"이 "interface"#include는 실장입니다.

언급URL : https://stackoverflow.com/questions/71105071/why-does-this-c-file-include-itself

반응형