매크로가 아직 정의되지 않은 경우에만 정의하는 이유는 무엇입니까?


93

C 코드베이스 전체에서 모든 매크로가 다음과 같이 정의 된 것을 볼 수 있습니다.

#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#endif

#ifndef BEEPTRIM_ROLL_RATE_DEGPS
#define BEEPTRIM_ROLL_RATE_DEGPS                    0.2f
#endif

#ifndef FORCETRIMRELEASE_HOLD_TIME_MS
#define FORCETRIMRELEASE_HOLD_TIME_MS               1000.0f
#endif

#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS       50.0f
#endif

매크로를 정의하는 대신 이러한 정의 검사를 수행하는 이유는 무엇입니까?

#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#define BEEPTRIM_ROLL_RATE_DEGPS                    0.2f
#define FORCETRIMRELEASE_HOLD_TIME_MS               1000.0f
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS       50.0f

웹에서이 관행이 설명 된 것을 찾을 수 없습니다.


6
코드의 다른 곳에서 상수를 변경하면 이러한 방식으로 작동합니다. 다른 누군가가 이러한 매크로 중 하나를 정의하는 경우이 파일을 구문 분석 할 때 전처리 기가 덮어 쓰지 않습니다.
Enzo Ferber 2015 년

8
WET 설계 원칙의 예입니다.
스타크

예제와 함께 답변을 게시했습니다. 컴파일 해보십시오.
Enzo Ferber 2015 년

답변:


141

이렇게하면 컴파일 할 때 매크로를 재정의 할 수 있습니다.

gcc -DMACRONAME=value

헤더 파일의 정의가 기본값으로 사용됩니다.


51

댓글에서 말했듯이 다음 상황을 상상해보십시오.

foo.h

#define FOO  4

defs.h

#ifndef FOO
#define FOO 6
#endif

#ifndef BAR
#define BAR 4
#endif

bar.c

#include "foo.h"
#include "defs.h"

#include <stdio.h>

int main(void)
{
    printf("%d%d", FOO, BAR);
    return 0;
}

인쇄 44됩니다.

그러나 조건부 ifndef가없는 경우 결과는 MACRO 재정의에 대한 컴파일 경고가되고 64.

$ gcc -o bar bar.c
In file included from bar.c:2:0:
defs.h:1:0: warning: "FOO" redefined [enabled by default]
 #define FOO 6
 ^
In file included from bar.c:1:0:
foo.h:1:0: note: this is the location of the previous definition
 #define FOO 4
 ^

1
이것은 컴파일러에 따라 다릅니다. 객체와 유사한 매크로를 재정의하는 것은 재정의가 "동일"하지 않는 한 불법입니다 (더 기술적 인 사양이 있지만 여기서는 중요하지 않습니다). 잘못된 코드는 진단이 필요하며, 진단 (여기서는 경고)을 발행하면 컴파일러는 구현 별 결과로 코드를 컴파일하는 것을 포함하여 모든 작업을 자유롭게 수행 할 수 있습니다.
Pete Becker

7
동일한 매크로에 대해 충돌 하는 정의 가있는 경우 대부분의 경우 경고를받지 않겠습니까? 첫 번째 정의를 조용히 사용하는 대신 (두 번째 정의는 ifdef재정의를 피하기 위해를 사용하기 때문입니다 ).
Peter Cordes

@PeterCordes 대부분의 경우 #infdefs 아래 의 정의 는 "대체"또는 "기본값"값으로 사용됩니다. 기본적으로 "사용자가 구성하면 괜찮습니다. 그렇지 않으면 기본값을 사용하겠습니다."
문헌 : Angew는 더 이상 자랑 SO의없는

@Angew : 좋아, 당신은 몇 가지가 그렇다면 #defines하여 라이브러리의 ABI의 일부인 라이브러리 헤더에, 당신은해야 하지 그들을 포장 #ifndef. (또는 더 나은 방법은 enum)를 사용하는 것 입니다. #ifndef한 컴파일 단위에 사용자 정의 정의가있는 경우에만 적합하지만 다른 컴파일 단위에는 적합하지 않음을 분명히하고 싶었습니다 . 경우 a.c와는 다른 순서로 헤더를 포함하고 b.c, 서로 다른의 정의를 얻을 수 있습니다 max(a,b), 그리고 함께 휴식 할 수 이러한 정의 중 하나 max(i++, x)지만, GNU 문 표현의 다른 힘의 사용 임시 변수. 적어도 혼란 스러워요!
Peter Cordes 2015 년

@PeterCordes 내가 그 경우에 할 좋아하는 것은#ifdef FOO #error FOO already defined! #endif #define FOO x
콜 존슨

17

컨텍스트를 모르지만 사용자에게 매크로 정의에 의해 설정된 값을 재정의 할 수있는 가용성을 제공하는 데 사용할 수 있습니다. 사용자가 이러한 매크로에 대해 다른 값을 명시 적으로 정의하면 여기에 사용 된 값 대신 사용됩니다.

예를 들어 g ++에서는 -D컴파일 중에 플래그를 사용하여 값을 매크로에 전달할 수 있습니다 .


14

이는 헤더 파일의 사용자가 자신의 코드 또는 컴파일러의 -D 플래그에서 정의를 대체 할 수 있도록 수행됩니다.


7

모든 C 프로젝트는 여러 소스 파일에 있습니다. 단일 소스 파일에 대해 작업 할 때 검사는 실제로 의미가없는 것처럼 보이지만 큰 C 프로젝트에서 작업 할 때는 상수를 정의하기 전에 기존 정의를 확인하는 것이 좋습니다. 아이디어는 간단합니다. 특정 소스 파일에 상수가 필요하지만 다른 소스 파일에 이미 정의되었을 수 있습니다.


2

사용자가 컴파일하고 작업 할 수있는 기본 사전 설정을 사용자에게 제공하는 프레임 워크 / 라이브러리에 대해 생각할 수 있습니다. 이러한 정의는 다른 파일에 분산되어 있으며 최종 사용자는 값을 구성 할 수있는 config.h 파일을 포함하는 것이 좋습니다. 사용자가 정의를 잊어 버린 경우 사전 설정으로 인해 시스템이 계속 작동 할 수 있습니다.


1

사용

#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#endif

사용자가 명령 줄 인수 (gcc / clang / VS)를 사용하여 매크로 값을 정의 할 수 있습니다 -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.

또 다른 중요한 이유가 있습니다. 전 처리기 매크로를 다르게 정의하는 것은 오류입니다. 다른 SO 질문에 대한 답변을 참조하십시오 . #ifndef검사가 없으면 -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f컴파일러 호출에서 명령 줄 인수로 사용되는 경우 컴파일러는 오류를 생성해야합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.