>백엔드 개발 >C++ >#define INC(a) INC(a ?

#define INC(a) INC(a ?

Susan Sarandon
Susan Sarandon원래의
2024-10-22 06:10:31578검색

#define INC(a) INC(a ?

이 매크로가 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를 사용하지만 다음과 같은 경우도 있습니다.

  • #ifdef
  • #if
  • #다른
  • #elif
#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__ 키워드를 사용한 것을 볼 수 있습니다.
상상할 수 있듯이 이는 컴파일러가 올바른 값으로 대체하는 매크로입니다.

공통 사전 정의 매크로 목록이 있습니다.

소위 시스템별 매크로가 있다는 점에 유의하세요.

완전하지 않은 작은 목록:

  • __날짜__: 2012년 1월 14일
  • __GNUC__: GCC의 주요 버전
  • __시간__: 15:12:18
  • __INCLUDE_LEVEL__: 0부터 시작하는 포함 깊이
  • __BASE_FILE__: 현재 파일 이름

무한을 향해 그리고 논쟁을 넘어서

#define SENS_DE_LA_VIE 3.14

/* ... */

printf("%f\n", SENS_DE_LA_VIE);

여기서 특히 로그를 생성할 때 유용한 가변 매크로를 생성하는 것을 볼 수 있습니다.
(printfs로 로그를 만드는 것은 좋은 생각이 아닐지라도.)

X-매크로

이를 위해 규칙은 없지만 흔히 *.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))

문제 #1

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__);

사용자가 무엇을 매개변수로 전달할지 알 수 없으므로 항상 인수에 괄호를 넣으세요.

문제 #2

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

이제 마무리할 시간입니다. 우리는 정말 멋진 것들을 많이 보았습니다. 그리고 유혹에 빠지면 자유롭게 매크로를 직접 발견할 수 있습니다. 아직 볼거리가 많습니다.
그래서 결론은: RTFM.

PS: 제목에 따르면 매크로는 재귀적이지 않으며 깊이 1로만 확장됩니다. 현재의 경우 GCC는 INC에 대해 implicit_declaration을 만들고 충돌합니다.

위 내용은 #define INC(a) INC(a ?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.