이 매크로가 GCC와 충돌합니까? 읽어보시면 답을 얻으실 수 있습니다
이 글의 목적은 여러분에게 C 매크로의 놀라운 세계를 소개하는 것입니다.
C에서 #으로 시작하는 줄은 소스 파일을 컴파일할 때 컴파일러에 의해 해석됩니다. 이를 전처리기 지시문이라고 합니다. 매크로도 그 중 하나입니다.
작은 역사적 지점:
C 언어 매크로는 ANSI C(또는 C89)라고 하는 최초의 C 언어 표준과 함께 도입되었습니다.
이는 1989년 미국표준협회(ANSI)에 의해 표준화되었습니다.그러나 이 표준화 이전에는 매크로는 이미 1970년대에 사용된 고전적인 C(또는 K&R C) 언어의 일부였습니다.
Dennis Ritchie가 UNIX 운영 체제용으로 개발한 원본 C 컴파일러에는 이미 전처리기를 통해 기본적인 형태의 매크로가 포함되어 있어 #define으로 정의할 수 있습니다.
#define SENS_DE_LA_VIE 3.14 /* ... */ printf("%f\n", SENS_DE_LA_VIE);
정의는 매우 이해하기 쉽게 작동합니다. 컴파일러는 코드의 모든 항목을 정의된 값으로 바꿉니다. 다음 구문 #define
약간 "Ctrl-f 및 바꾸기"와 비슷합니다.
정의를 사용하여 코드에서 사용할 수 있는 함수를 정의할 수 있습니다.
#define INC(a) a++ #define MULTI_LINE(a,b) a = b; \ b = 0; INC(my_variable); MULTI_LINE(my_variable, foobar) // Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne // Cela donnera my_variable++; my_variable = foobar; foobar = 0;
조건부로 매크로를 선언할 수 있습니다.
이름이 이미 정의되어 있으면 다음 코드를 실행합니다.
#ifdef DEBUG // Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug // et que nous avons brisé la règle du nom des macros en MAJ. #define return printf("(%s:%d)\n", __FUNCTION__, __LINE__); return #endif /* ! DEBUG */ int main(void) { return 1; }
이 경우에는 #ifndef를 사용하지만 다음과 같은 경우도 있습니다.
#if (X == 1) #define Y 2 #elif (X == 2) #define Y "Ami de la bonne blague, bonjour !" #else #define Y NULL #endif /* ! X */ /* ... */ int main(void) { #if (X == 1) printf("%d\n", Y); #elif (X == 2) printf("%s\n", Y); #else printf("%p\n", Y); #endif /* ! X */ }
대량댓글로 #if의 끝을 알리고 싶습니다. 이는 코드를 더 잘 탐색할 수 있게 해주는 규칙입니다.
이전 예에서 __FUNCTION__ 및 __LINE__ 키워드를 사용한 것을 볼 수 있습니다.
상상할 수 있듯이 이는 컴파일러가 올바른 값으로 대체하는 매크로입니다.
공통 사전 정의 매크로 목록이 있습니다.
소위 시스템별 매크로가 있다는 점에 유의하세요.
완전하지 않은 작은 목록:
#define SENS_DE_LA_VIE 3.14 /* ... */ printf("%f\n", SENS_DE_LA_VIE);
여기서 특히 로그를 생성할 때 유용한 가변 매크로를 생성하는 것을 볼 수 있습니다.
(printfs로 로그를 만드는 것은 좋은 생각이 아닐지라도.)
이를 위해 규칙은 없지만 흔히 *.def라는 이름의 외부 파일을 만들어야 합니다.
#define INC(a) a++ #define MULTI_LINE(a,b) a = b; \ b = 0; INC(my_variable); MULTI_LINE(my_variable, foobar) // Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne // Cela donnera my_variable++; my_variable = foobar; foobar = 0;
#ifdef DEBUG // Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug // et que nous avons brisé la règle du nom des macros en MAJ. #define return printf("(%s:%d)\n", __FUNCTION__, __LINE__); return #endif /* ! DEBUG */ int main(void) { return 1; }
이런 종류의 매크로는 매우 유용합니다. 소스 코드에서는 거의 발견되지 않는다는 점을 인정해야 하지만 소스 코드를 수정하지 않고도 프로그램의 작동을 수정할 수 있습니다. 재미있는 사실은 커널 생성에 자주 사용된다는 것입니다. 이를 통해 IDT 및 GDT와 같은 전역 구조를 생성할 수 있습니다.
주의: 먼저 간단히 설명하자면 매크로는 훌륭한 도구이지만 조심해야 합니다. 이런 유형의 매크로는 절대로 사용하면 안 됩니다.
#if (X == 1) #define Y 2 #elif (X == 2) #define Y "Ami de la bonne blague, bonjour !" #else #define Y NULL #endif /* ! X */ /* ... */ int main(void) { #if (X == 1) printf("%d\n", Y); #elif (X == 2) printf("%s\n", Y); #else printf("%p\n", Y); #endif /* ! X */ }
예를 들어보겠습니다: MIN(2 5, fibo(25))
MIN(2 5, fibo(25)) => (2 5
여기서 문제는 계산 우선순위입니다. 컴파일러는 먼저 비교를 수행한 다음 추가를 수행하므로 2(1)이 됩니다. 매크로 인수를 사용하여 괄호를 추가하여 이를 수정합니다.
// Ici, l'opérateur ## est l'opérateur de concaténation #define DEBUG_PRNTF(fmt, ...) printf("LOG" ## fmt, __VA_ARGS__);
사용자가 무엇을 매개변수로 전달할지 알 수 없으므로 항상 인수에 괄호를 넣으세요.
MIN(2 5, fibo(25)) => (2 5
우리는 컴파일러가 어리 석고 불쾌한 교체를 수행한다는 것을 알았습니다. 이는 fibo(25)를 두 번 계산한다는 의미입니다. 재귀적 구현인지 상상해 보도록 하겠습니다.
이 문제를 해결하기 위해 if 앞에 중간 변수를 선언합니다.
// color.def X(NC, "\e[0m", "No Color", 0x000000) X(BLACK, "\e[0;30m", "Black", 0x000000) X(GRAY, "\e[1;30m", "Gray", 0x808080) X(RED, "\e[0;31m", "Red", 0xFF0000) X(LIGHT_RED, "\e[1;31m", "Light Red", 0xFF8080) X(GREEN, "\e[0;32m", "Green", 0x00FF00) X(LIGHT_GREEN, "\e[1;32m", "Light Green", 0x80FF80) X(BROWN, "\e[0;33m", "Brown", 0xA52A2A) X(YELLOW, "\e[1;33m", "Yellow", 0xFFFF00) X(BLUE, "\e[0;34m", "Blue", 0x0000FF) X(LIGHT_BLUE, "\e[1;34m", "Light Blue", 0xADD8E6) X(PURPLE, "\e[0;35m", "Purple", 0x800080) X(LIGHT_PURPLE, "\e[1;35m", "Light Purple", 0xEE82EE) X(CYAN, "\e[0;36m", "Cyan", 0x00FFFF) X(LIGHT_CYAN, "\e[1;36m", "Light Cyan", 0xE0FFFF) X(LIGHT_GRAY, "\e[0;37m", "Light Gray", 0xD3D3D3) X(WHITE, "\e[1;37m", "White", 0xFFFFFF)
여기서는 단지 재미를 위한 순전히 과도한 코드입니다. 코드에 이러한 매크로를 사용하도록 반드시 권장하지는 않습니다.
나는 단지 즐거운 시간을 보내고 있습니다(인생의 좋은 일).
typedef struct { const char *name; const char *ansi_code; const char *description; unsigned int rgb; } Color; #define X(NAME, ANSI, DESC, RGB) { #NAME, ANSI, DESC, RGB }, Color colors[] = { #include "color.def" }; #undef X #define X(NAME, ANSI, DESC, RGB) printf("%s (%s) = %s\n", #NAME, DESC, #RGB); void print_colors() { // Bien entendu, on pourrait itérer sur la structure créée mais c'est une illustration #include "color.def" } #undef X
약간의 -fsanitize=address를 사용하여 테스트해 보겠습니다. 정말 미쳤어요. 전환을 위해 구조 이름의 문자열을 매개변수로 사용하는 auto_free 함수의 개선도 확인할 수 있었습니다.
함수 실행 시간만 계산하는 추가 냉각 기능입니다. 벤치마킹에 매우 유용합니다.
#define SENS_DE_LA_VIE 3.14 /* ... */ printf("%f\n", SENS_DE_LA_VIE);
매크로를 인수로 받아 확장하는 작은 X-매크로입니다.
#define INC(a) a++ #define MULTI_LINE(a,b) a = b; \ b = 0; INC(my_variable); MULTI_LINE(my_variable, foobar) // Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne // Cela donnera my_variable++; my_variable = foobar; foobar = 0;
C에는 제한이 없기 때문에 실제로 매크로를 사용하여 전체 함수를 생성합니다. 나도요?
#ifdef DEBUG // Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug // et que nous avons brisé la règle du nom des macros en MAJ. #define return printf("(%s:%d)\n", __FUNCTION__, __LINE__); return #endif /* ! DEBUG */ int main(void) { return 1; }
이제 마무리할 시간입니다. 우리는 정말 멋진 것들을 많이 보았습니다. 그리고 유혹에 빠지면 자유롭게 매크로를 직접 발견할 수 있습니다. 아직 볼거리가 많습니다.
그래서 결론은: RTFM.
PS: 제목에 따르면 매크로는 재귀적이지 않으며 깊이 1로만 확장됩니다. 현재의 경우 GCC는 INC에 대해 implicit_declaration을 만들고 충돌합니다.
위 내용은 #define INC(a) INC(a ?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!