#ifdef vs #if- 특정 ​​코드 섹션의 컴파일을 활성화/비활성화하는 방법으로 더 나은/더 안전합니까?

StackOverflow https://stackoverflow.com/questions/135069

문제

이것은 스타일의 문제 일지 모르지만 우리의 개발자 팀에는 약간의 분열이 있으며 다른 사람이 그 문제에 대한 아이디어가 있는지 궁금했습니다 ...

기본적으로 정상적인 개발 중에 꺼지는 디버그 인쇄문이 있습니다. 개인적으로 나는 다음을 선호합니다.

//---- SomeSourceFile.cpp ----

#define DEBUG_ENABLED (0)

...

SomeFunction()
{
    int someVariable = 5;

#if(DEBUG_ENABLED)
    printf("Debugging: someVariable == %d", someVariable);
#endif
}

팀 중 일부는 다음을 선호합니다.

// #define DEBUG_ENABLED

...

SomeFunction()
{
    int someVariable = 5;

#ifdef DEBUG_ENABLED
    printf("Debugging: someVariable == %d", someVariable);
#endif
}

... 그 중 어떤 방법이 당신에게 더 잘 들리며 그 이유는 무엇입니까? 내 느낌은 항상 정의 된 것이 있고 다른 곳에서 다른 정의를 파괴 할 수있는 위험이 없기 때문에 첫 번째는 더 안전하다는 것입니다.

도움이 되었습니까?

해결책

나의 초기 반응은했다 #ifdef, 물론이야, 하지만 나는 생각해 #if 실제로 이것에 대한 몇 가지 중요한 이점이 있습니다. 이유는 다음과 같습니다.

먼저 사용할 수 있습니다 DEBUG_ENABLED 전처리에서 그리고 컴파일 된 테스트. 예 - 종종 디버그가 활성화 될 때 더 긴 시간 초과를 원하므로 사용하십시오. #if, 나는 이것을 쓸 수있다

  DoSomethingSlowWithTimeout(DEBUG_ENABLED? 5000 : 1000);

... 대신에 ...

#ifdef DEBUG_MODE
  DoSomethingSlowWithTimeout(5000);
#else
  DoSomethingSlowWithTimeout(1000);
#endif

둘째, 당신은 당신이 #define 글로벌 상수에. #defineS는 일반적으로 대부분의 C ++ 프로그래머에 의해 눈살을 찌푸립니다.

그리고 셋째, 당신은 당신이 당신의 팀을 분할한다고 말합니다. 내 생각에 이것은 다른 회원들이 이미 다른 접근법을 채택했으며 표준화해야한다는 것을 의미합니다. 판결 #if 선호하는 선택은 해당 코드를 사용하는 것을 의미합니다 #ifdef 언제라도 컴파일됩니다 DEBUG_ENABLED 거짓입니다. 그리고 그것은입니다 많이 추적하고 그 반대가 아닌 경우 생성되는 디버그 출력을 쉽게 제거하고 제거 할 수 있습니다.

아, 그리고 작은 가독성 지점. 0/1 대신 True/False를 사용할 수 있어야합니다. #define, 값은 단일 어휘 토큰이기 때문에 주변의 괄호가 필요하지 않습니다.

#define DEBUG_ENABLED true

대신에

#define DEBUG_ENABLED (1)

다른 팁

둘 다 끔찍합니다. 대신, 이것을 수행하십시오 :

#ifdef DEBUG
#define D(x) do { x } while(0)
#else
#define D(x) do { } while(0)
#endif

그런 다음 디버그 코드가 필요할 때마다 안에 넣으십시오. D();. 그리고 당신의 프로그램은 끔찍한 미로로 오염되지 않습니다 #ifdef.

#ifdef 주어진 토큰이 정의되어 있는지 확인하십시오

#define FOO 0

그 다음에

#ifdef FOO // is true
#if FOO // is false, because it evaluates to "#if 0"

우리는 여러 파일에서 동일한 문제를 겪었으며 사람들이 "피처 플래그"파일을 포함하는 것을 잊어 버리는 사람들에게는 항상 문제가 있습니다 (코드베이스는> 41,000 파일이 쉽습니다).

기능이 있다면 H :

#ifndef FEATURE_H
#define FEATURE_H

// turn on cool new feature
#define COOL_FEATURE 1

#endif // FEATURE_H

그러나 파일에 헤더 파일을 포함시키는 것을 잊었습니다.

#if COOL_FEATURE
    // definitely awesome stuff here...
#endif

그런 다음 문제가 발생하면 컴파일러는이 경우 Cool_Feature가 "False"로 정의되지 않은 것으로 해석하고 코드를 포함하지 않습니다. 예 GCC는 정의되지 않은 매크로에 오류를 일으키는 플래그를 지원하지만 대부분의 타사 코드는 기능을 정의하거나 정의하지 않으므로 휴대용이 아닙니다.

우리는이 케이스에 대한 휴대용 방법을 채택하고 기능 매크로 기능을 테스트했습니다.

위의 기능을 변경 한 경우 :

#ifndef FEATURE_H
#define FEATURE_H

// turn on cool new feature
#define COOL_FEATURE() 1

#endif // FEATURE_H

그러나 다시 파일에 헤더 파일을 포함시키는 것을 잊었습니다.

#if COOL_FEATURE()
    // definitely awseome stuff here...
#endif

정의되지 않은 함수 매크로의 사용으로 인해 사전 처리기가 오류가 발생했을 것입니다.

조건부 편집을 수행하기 위해 #if 및 #ifdef가 거의 동일하지만 그다지 그렇지는 않습니다. 조건부 편집이 두 기호에 의존하는 경우 #ifdef도 작동하지 않습니다. 예를 들어, 두 가지 조건부 컴파일 기호, pro_version 및 river_version이 있다고 가정하면 다음과 같은 것이있을 수 있습니다.

#if defined(PRO_VERSION) && !defined(TRIAL_VERSION)
...
#else
...
#endif

#ifdef를 사용하면 위의 것이 훨씬 더 복잡해지며, 특히 #ELSE 부분이 작동하도록합니다.

조건부 컴파일을 광범위하게 사용하는 코드에서 작업하고 있으며 #IF & #ifdef가 혼합되어 있습니다. 우리는 간단한 경우에 #ifdef/ #ifndef를 사용하는 경향이 있으며 두 개 이상의 기호가 평가 될 때마다 #if #.

나는 그것이 전적으로 스타일의 문제라고 생각합니다. 다른 사람보다 명백한 이점도 없습니다.

일관성은 특정 선택보다 더 중요하므로 팀과 함께 하나의 스타일을 선택하고이를 고수하는 것이 좋습니다.

나는 나 자신을 선호한다 :

#if defined(DEBUG_ENABLED)

반대 조건을 찾는 코드를 쉽게 만들 수있게되므로 훨씬 쉽게 찾을 수 있습니다.

#if !defined(DEBUG_ENABLED)

vs.

#ifndef(DEBUG_ENABLED)

스타일의 문제입니다. 그러나 더 간결한 방법을 추천합니다.

#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print
#endif

debug_print("i=%d\n", i);

이 작업을 한 번 수행 한 다음 항상 Debug_print ()를 사용하여 인쇄하거나 아무것도하지 않습니다. (예, 이것은 두 경우 모두 컴파일됩니다.) 이런 식으로, 당신의 코드는 전처리 서기 지시문으로 장식되지 않습니다.

"표현식이 효과가 없다"는 경고를 받고 그것을 제거하고 싶다면 다음은 대안입니다.

void dummy(const char*, ...)
{}

#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print dummy
#endif

debug_print("i=%d\n", i);

#if 스위치가 있음을 감지하면서 기능을 끄기 위해 0으로 설정하는 옵션을 제공합니다.
개인적으로 나는 항상 #define DEBUG 1 그래서 나는 #if 또는 #ifdef로 그것을 잡을 수 있습니다

#if 및 #define my_macro (0)

#if를 사용한다는 것은 "정의"매크로, 즉 "(0)로 대체 할 코드에서 검색 될"매크로 정의 "매크로를 만들었다는 것을 의미합니다. 이것은 C ++에서보고 싶어하는 "매크로 지옥"입니다. 왜냐하면 그것은 잠재적 코드 수정으로 코드를 오염시키기 때문입니다.

예를 들어:

#define MY_MACRO (0)

int doSomething(int p_iValue)
{
   return p_iValue + 1 ;
}

int main(int argc, char **argv)
{
   int MY_MACRO = 25 ;
   doSomething(MY_MACRO) ;

   return 0;
}

g ++에 다음 오류가 발생합니다.

main.cpp|408|error: lvalue required as left operand of assignment|
||=== Build finished: 1 errors, 0 warnings ===|

하나 오류.

즉, 매크로가 C ++ 코드와 성공적으로 상호 작용했음을 의미합니다. 기능에 대한 호출이 성공했습니다. 이 간단한 경우에는 재미 있습니다. 그러나 내 코드로 조용히 연주하는 매크로에 대한 나의 경험은 기쁨과 풀 필러로 가득 차 있지 않습니다.

#ifdef 및 #define my_macro

#ifdef를 사용한다는 것은 무언가를 "정의"하는 것을 의미합니다. 당신이 가치를주는 것은 아닙니다. 여전히 오염이지만 적어도 "아무것도 대체"되며 C ++ 코드는 Lagitimate Code 문으로 보이지 않습니다. 간단한 정의와 함께 위의 동일한 코드는 다음과 같습니다.

#define MY_MACRO

int doSomething(int p_iValue)
{
   return p_iValue + 1 ;
}

int main(int argc, char **argv)
{
   int MY_MACRO = 25 ;
   doSomething(MY_MACRO) ;

   return 0;
}

다음 경고를 제공합니다.

main.cpp||In function ‘int main(int, char**)’:|
main.cpp|406|error: expected unqualified-id before ‘=’ token|
main.cpp|399|error: too few arguments to function ‘int doSomething(int)’|
main.cpp|407|error: at this point in file|
||=== Build finished: 3 errors, 0 warnings ===|

그래서...

결론

차라리 내 코드에서 매크로없이 살고 싶지만 여러 가지 이유 (헤더 가드 정의 또는 디버그 매크로).

그러나 적어도, 나는 합법적 인 C ++ 코드로 대화식이 가장 적을 수있게하고 싶습니다. 이는 값없이 #define을 사용하고 #ifdef 및 #ifndef (또는 Jim Buck이 제안한대로 정의 된 #if)를 사용하는 것을 의미하며, 무엇보다도 이름을 너무 길고 외계인을 사용하지 않습니다. 그것은 "우연히", 그리고 그것은 결코 합법적 인 C ++ 코드에 영향을 미치지 않을 것입니다.

포스트 Scriptum

이제 내 게시물을 다시 읽을 때, 내 정의에 추가 할 C ++가 맞지 않는 값을 찾지 않아야하는지 궁금합니다. 같은 것

#define MY_MACRO @@@@@@@@@@@@@@@@@@

#ifdef 및 #ifndef와 함께 사용할 수는 있지만 함수 내에서 사용하면 코드 컴파일을 작성하지 못하게합니다 ... G ++에서 성공적으로 시도해 보았습니다. 오류가 발생했습니다.

main.cpp|410|error: stray ‘@’ in program|

흥미로운. :-)

첫 번째는 나에게 더 명확 해 보인다. 정의/정의되지 않은 것과 비교하여 더 자연스럽게 보이는 것처럼 보입니다.

둘 다 정확히 동일합니다. 관용적으로 사용하면 #ifdef는 정의 성 (및 예제에서 사용하는 내용)을 확인하는 데 사용되는 반면 #if는 #if 정의 (a) && defined (b)와 같은보다 복잡한 표현식에 사용됩니다.

약간의 구약이지만 전처리기로 로깅을 켜거나 끄는 것은 C ++에서 분명히 차선책입니다. Apache 's와 같은 멋진 로깅 도구가 있습니다 log4cxx 오픈 소스이며 응용 프로그램을 배포하는 방법을 제한하지 않습니다. 또한 재 컴파일없이 로깅 레벨을 변경하고 로깅을 끄면 오버 헤드가 매우 낮으며 생산에서 완전히 로그를 끄는 기회를 제공합니다.

그것은 전혀 스타일의 문제가 아닙니다. 또한 질문은 불행히도 잘못입니다. 더 나은 또는 더 안전한 의미 에서이 전처리 서기 지시문을 비교할 수 없습니다.

#ifdef macro

"매크로가 정의 된 경우"또는 "매크로가 존재하는 경우"를 의미합니다. 매크로의 가치는 여기서 중요하지 않습니다. 그것은 무엇이든 될 수 있습니다.

#if macro

항상 값과 비교하는 경우. 위의 예에서는 표준 암시 적 비교입니다.

#if macro !=0

#if 사용에 대한 예

#if CFLAG_EDITION == 0
    return EDITION_FREE;
#elif CFLAG_EDITION == 1
    return EDITION_BASIC;
#else
    return EDITION_PRO;
#endif

이제 CFLAG_EDITION의 정의를 코드에 넣을 수 있습니다.

#define CFLAG_EDITION 1 

또는 매크로를 컴파일러 플래그로 설정할 수 있습니다. 또한 여기를 봐.

나는 사용했었다 #ifdef, 그러나 문서화를 위해 Doxygen으로 전환했을 때, 주석은 매크로를 문서화 할 수 없다는 것을 알았습니다 (또는 적어도 Doxygen은 경고를 생성합니다). 즉, 현재 활성화되지 않은 기능 스위치 매크로를 문서화 할 수 없습니다.

Doxygen에 대해서만 매크로를 정의 할 수는 있지만, 이는 코드의 비활성 부분의 매크로도 문서화 될 것임을 의미합니다. 개인적으로 기능 스위치를 표시하고 그렇지 않으면 현재 선택된 내용 만 문서화하고 싶습니다. 또한 Doxygen이 파일을 처리 할 때만 정의 해야하는 많은 매크로가 있으면 코드가 매우 지저분 해집니다.

따라서이 경우 항상 매크로를 정의하고 사용하는 것이 좋습니다. #if.

나는 항상 #ifdef 및 컴파일러 플래그를 사용하여 정의했습니다 ...

또는 전역 상수를 선언하고 전처리 기 #IF 대신 C ++를 사용할 수 있습니다. 컴파일러는 사용하지 않은 분기를 최적화해야하며 코드는 더 깨끗합니다.

여기에 무엇이 있습니다 C ++ gotchas Stephen C. Dewhurst는 #if 's를 사용하는 것에 대해 말합니다.

운전자에게 조건부 정의를 지정하는 다른 방법의 경우 차이가 있습니다.

diff <( echo | g++ -DA= -dM -E - ) <( echo | g++ -DA -dM -E - )

산출:

344c344
< #define A 
---
> #define A 1

이것은 그것을 의미합니다 -DA 동의어입니다 -DA=1 그리고 가치가 생략되면 #if A 용법.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top