#ifdef vs #if - 특정 코드 섹션의 컴파일을 활성화/활성화하는 방법으로는 어떤 것이 더 좋습니까?
이건 스타일의 문제일 수도 있지만, 우리 개발팀에는 약간의 차이가 있어. 그리고 나는 이 문제에 대해 다른 누군가가 다른 생각을 가지고 있는지 궁금했다.
기본적으로 디버깅 인쇄 문장이 몇 개 있는데, 일반 개발 중에는 이 문장이 꺼집니다.개인적으로 저는 다음 일을 하는 것을 선호합니다.
//---- 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
되어 있는지 합니다.
#define FOO 0
그리고나서
#ifdef FOO // is true
#if FOO // is false, because it evaluates to "#if 0"
물론 제 첫 반응은요, 하지만 제 생각에는#if
하면 큰 과 같습니다.그 이유는 다음과 같습니다.
먼저 '아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.DEBUG_ENABLED
preprocessor 및 컴파일된 테스트에 포함되어 있습니다.예: 보통 디버깅을 활성화하면 타임아웃이 길어지기 때문에#if
는 이걸 쓸 수 있어요.
DoSomethingSlowWithTimeout(DEBUG_ENABLED? 5000 : 1000);
...대신...
#ifdef DEBUG_MODE
DoSomethingSlowWithTimeout(5000);
#else
DoSomethingSlowWithTimeout(1000);
#endif
번째, 이행을 싶을 것이 .#define
글로벌 상수로 변환합니다. #define
s는 대부분의 C++ 프로그래머에 의해 보통 눈살을 찌푸리게 됩니다.
셋째, 팀원들 사이에 격차가 있다고 합니다.제 생각에는 이것은 다른 구성원들이 이미 다른 접근법을 채택했다는 것을 의미하며, 당신은 표준화가 필요하다는 것입니다.라고 #if
는 " "를 사용하는 "를 합니다.#ifdef
하여 DEBUG_ENABLED
거짓입니다.또한 디버깅 출력을 추적하여 삭제해야 할 때 발생하는 디버깅 출력을 삭제하는 것이 그 반대보다 훨씬 쉽습니다.
아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아. 이면 참/거짓은 이 아니라 참/할 수 .#define
이 값은 단일 어휘 토큰이므로 괄호가 필요하지 않습니다.
#define DEBUG_ENABLED true
대신
#define DEBUG_ENABLED (1)
여러 파일에 걸쳐 동일한 문제가 발생했으며, 사용자가 "기능 플래그" 파일을 포함시키지 않는 문제가 항상 발생합니다(코드베이스가 41,000개 이상이면 쉽게 수행할 수 있습니다).
이목구비가 있다면.h:
#ifndef FEATURE_H
#define FEATURE_H
// turn on cool new feature
#define COOL_FEATURE 1
#endif // FEATURE_H
그런데 헤더 파일을 file.cpp에 포함시키지 않았습니다.
#if COOL_FEATURE
// definitely awesome stuff here...
#endif
그러면 문제가 발생합니다.컴파일러는 COOL_FEATURE가 정의되지 않은 것을 이 경우 "false"로 해석하여 코드를 포함시키지 못합니다.네, gcc는 정의되지 않은 매크로에 대해 오류를 일으키는 플래그를 지원합니다.그러나 대부분의 서드파티 코드는 기능을 정의하거나 정의하지 않기 때문에 휴대성은 그다지 높지 않습니다.
이 문제를 수정하기 위한 휴대용 방법 및 기능 상태를 테스트하기 위한 방법인 기능 매크로를 채택했습니다.
위의 feature.h를 다음과 같이 변경했을 경우:
#ifndef FEATURE_H
#define FEATURE_H
// turn on cool new feature
#define COOL_FEATURE() 1
#endif // FEATURE_H
그러나 다시 헤더 파일을 file.cpp에 포함시키는 것을 잊었습니다.
#if COOL_FEATURE()
// definitely awseome stuff here...
#endif
정의되지 않은 함수 매크로가 사용되었기 때문에 프리프로세서가 에러를 일으켰을 가능성이 있습니다.
둘 다 끔찍해대신 다음을 수행합니다.
#ifdef DEBUG
#define D(x) do { x } while(0)
#else
#define D(x) do { } while(0)
#endif
디버깅코드가마다 안에 .D();
당신의 은 끔찍한 로 오염되지#ifdef
.
드라이버에 조건부 정의를 지정하는 방법이 다른 경우 다음과 같은 차이가 있습니다.
diff <( echo | g++ -DA= -dM -E - ) <( echo | g++ -DA -dM -E - )
출력:
344c344
< #define A
---
> #define A 1
①은-DA
입니다.-DA=1
수 .#if A
usagedisplays..
조건부 컴파일을 수행하기 위해 #if와 #ifdef는 거의 동일하지만 완전히 동일하지는 않습니다.조건부 컴파일이 2개의 기호에 의존할 경우 #ifdef도 기능하지 않습니다.예를 들어 PRO_VERSION과 TRIMAL_VERSION이라는 두 가지 조건부 컴파일 기호가 있다고 가정하면 다음과 같습니다.
#if defined(PRO_VERSION) && !defined(TRIAL_VERSION)
...
#else
...
#endif
#ifdef를 사용하면 위의 내용이 훨씬 복잡해집니다.특히 #else 파트를 사용할 수 있게 됩니다.
저는 조건부 컴파일을 광범위하게 사용하는 코드를 연구하고 있으며, #if와 #ifdef가 혼합되어 있습니다.간단한 경우 #ifdef/#ifndef를 사용하고 두 개 이상의 기호가 평가될 경우 #iffndef를 사용하는 경향이 있습니다.
그것은 전혀 스타일의 문제가 아니다.그리고 불행히도 그 질문은 틀렸다.이러한 프리프로세서의 디렉티브는, 보다 우수하거나 안전하다고는 비교할 수 없습니다.
#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_EDION의 정의를 코드에 넣을 수 있습니다.
#define CFLAG_EDITION 1
또는 매크로를 컴파일러 플래그로 설정할 수 있습니다.여기도 봐주세요.
내 생각에 이건 완전히 스타일의 문제인 것 같아.어느 쪽도 다른 쪽보다 확실한 우위성을 가지고 있지 않다.
어느 쪽이든 일관성이 중요하기 때문에 팀원들과 함께 한 가지 스타일을 선택하고 그것을 고수하는 것을 추천합니다.
#if
그럼 스위치가 존재하는 것을 검출하면서 기능을 끄기 위해 이 옵션을 0으로 설정할 수 있습니다.
는 개인적으로 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」#define DEBUG 1
또는 #if #if #if # #iff로 잡을 수 .
나 자신은 다음을 선호한다.
#if defined(DEBUG_ENABLED)
반대 조건을 찾는 코드를 쉽게 만들 수 있으므로 다음과 같이 하십시오.
#if !defined(DEBUG_ENABLED)
대.
#ifndef(DEBUG_ENABLED)
그것은 스타일의 문제이다.다만, 보다 간결한 방법을 추천합니다.
#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print
#endif
debug_print("i=%d\n", i);
이 작업을 한 번 수행한 후 항상 debug_print()를 사용하여 인쇄하거나 아무것도 수행하지 않습니다(예, 두 경우 모두 컴파일됩니다).이렇게 하면 프리프로세서 지시로 인해 코드가 왜곡되지 않습니다.
expression is not effect(표현식 효과가 없습니다)라는 경고가 표시되어 이를 제거하려면 다음 방법을 사용할 수 있습니다.
void dummy(const char*, ...)
{}
#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print dummy
#endif
debug_print("i=%d\n", i);
#if 및 #정의 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 ===|
오류는 1개뿐입니다.
즉, 매크로가 C++ 코드와 정상적으로 상호 작용한 것을 의미합니다.함수에 대한 호출이 성공했습니다.이 간단한 경우, 재미있습니다.하지만 매크로가 내 코드로 소리 없이 재생되는 내 경험은 기쁨과 만족으로 가득 차진 않아, 그래서...
#ifdef 및 #define MY_MACRO
#ifdef를 사용하는 것은 무언가를 "정의"하는 것을 의미합니다.가치를 주는 게 아니라이것은 여전히 오염시키고 있지만, 적어도 "아무것도 없는" 것으로 대체되며, C++ 코드에 의해 시차 코드 문장으로 인식되지 않습니다.위의 코드와 심플한 정의로 다음과 같습니다.
#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 in value, #ifdef 및 #ifndef(또는 Jim Buck이 제안한 #fndef)를 사용합니다.또, 무엇보다도, 그 이름에 너무 길고 이상한 이름을 붙이는 것은, 「우연」이라고 하는 것은 아니고, 정당한 C++코드에 영향을 주지 않습니다.
투고 스크립트
투고를 다시 읽으면서 정의에 추가할 수 있는 C++가 결코 정확하지 않은 값을 찾아야 할지 고민하게 되었습니다.뭐랄까
#define MY_MACRO @@@@@@@@@@@@@@@@@@
#ifdef 및 #ifndef와 함께 사용할 수 있지만 함수 내에서 사용할 경우 코드가 컴파일되지 않습니다.g++에서 정상적으로 시도했더니 다음 오류가 발생하였습니다.
main.cpp|410|error: stray ‘@’ in program|
흥미롭습니다. :-)
에는 ★★★★★★★★★★★★★★★★★★★★★.#ifdef
그러나 문서화를 위해 Doxygen으로 전환했을 때 코멘트 아웃 매크로는 문서화할 수 없습니다(또는 적어도 Doxygen은 경고를 생성합니다).즉, 현재 이니블로 되어 있지 않은 기능 스위치매크로는 문서화할 수 없습니다.
Doxygen에 대해서만 매크로를 정의할 수 있지만, 이는 코드의 비액티브 부분에 있는 매크로도 문서화됨을 의미합니다.개인적으로 기능 스위치를 표시하고, 그렇지 않으면 현재 선택된 기능만 문서화하려고 합니다.또한 Doxygen이 파일을 처리할 때만 정의해야 하는 매크로가 많으면 코드가 상당히 복잡해집니다.
하고 ""를 사용하는 것이 .#if
.
약간 OT이지만 프리프로세서를 사용한 로깅의 온/오프는 확실히 C++에서는 최적이라고는 할 수 없습니다.Apache의 log4cxx와 같은 훌륭한 로깅 툴은 오픈 소스이며 응용 프로그램 배포 방법을 제한하지 않습니다.또한 재컴파일 없이 로깅 수준을 변경할 수 있으며, 로그가 꺼지면 오버헤드가 매우 낮으며 운영 환경에서 로그를 완전히 끌 수 있습니다.
첫 번째는 내게 더 명확해 보인다.정의되어 있거나 정의되어 있지 않은 경우에 비해 플래그가 되는 것이 더 자연스러운 것 같습니다.
둘 다 똑같아요.관용적인 사용법에서는 #ifdef는 정의되어 있는지 확인하기 위해서만 사용되며(그리고 이 예에서는 무엇을 사용하고 있는지), #iff는 #ifdefined(A) &!defined(B)와 같이 보다 복잡한 표현에서 사용됩니다.
항상 #ifdef 및 컴파일러 플래그를 사용하여 정의해 왔습니다.
또는 글로벌 상수를 선언하고 프리프로세서 #if 대신 C++ if 를 사용할 수도 있습니다.컴파일러는 사용하지 않는 브랜치를 최적화하여 코드를 깔끔하게 합니다.
Stephen C의 C++ Gotchas는 다음과 같습니다.Dewurst는 #if's 사용에 대해 말합니다.
좋아해요#define DEBUG_ENABLED (0)
여러 수준의 디버깅이 필요할 수 있습니다.예를 들어 다음과 같습니다.
#define DEBUG_RELEASE (0)
#define DEBUG_ERROR (1)
#define DEBUG_WARN (2)
#define DEBUG_MEM (3)
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL (DEBUG_RELEASE)
#endif
//...
//now not only
#if (DEBUG_LEVEL)
//...
#endif
//but also
#if (DEBUG_LEVEL >= DEBUG_MEM)
LOG("malloc'd %d bytes at %s:%d\n", size, __FILE__, __LINE__);
#endif
메모리 누수를 쉽게 디버깅할 수 있습니다.다른 것을 디버깅할 때 로그 행을 사용하지 않아도 됩니다.
또,#ifndef
를 사용하면 명령줄에서 특정 디버깅레벨을 쉽게 선택할 수 있습니다.
make -DDEBUG_LEVEL=2
cmake -DDEBUG_LEVEL=2
etc
이게 아니었으면 내가 유리했을 텐데#ifdef
컴파일러/make 플래그가 파일 내의 플래그로 덮어쓰기되기 때문입니다.따라서 커밋을 수행하기 전에 헤더를 다시 변경할 필요가 없습니다.
많은 것들이 그렇듯이, 답은 다르다. #ifdef
특정 단위로 정의되거나 정의되지 않은 항목에 적합합니다.예를 들어 가드를 포함합니다.포함 파일이 한 번 이상 있으면 기호가 정의되고 그렇지 않으면 정의되지 않습니다.
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★♪로 생각해 보세요.HAS_FEATURE_X
몇의개 가가 ?? ???
- 정의되어 있지 않다
- 정의되어 있다
- 값(0 또는 1)으로 정의됩니다.
코드, 코드를 에는 코드, 코드, 코드, 코드, , 코드, 코드, 코드, 코드, 코드, 코드, 코드, 코드, 코드, 코드, 코드, 코드 이 있습니다.#define HAS_FEATURE_X 0
즉, 기능 X가 존재하지 않고 다른 사용자가 정의하지 않을 수 있으므로 이러한 모든 경우를 처리해야 합니다.
#if !defined(HAS_FEATURE_X) || HAS_FEATURE_X == 1
★★★★만 #ifdef
누군가 또는 일부 팀이 사용하지 않는 것을 0으로 정의하는 규칙을 가지고 있기 때문에 예기치 않게 무언가가 전환(또는 꺼짐)되는 미묘한 오류가 발생할 수 있습니다.면에서는 저는 이런 것을 .#if
왜냐하면 프로그래머가 적극적으로 결정을 내렸다는 것을 의미하기 때문이다.정의되지 않은 것을 방치하는 것은 수동적이며, 외부적인 관점에서 보면 그것이 의도적인 것인지 아니면 부주의한 것인지 불분명할 수 있다.
언급URL : https://stackoverflow.com/questions/135069/ifdef-vs-if-which-is-better-safer-as-a-method-for-enabling-disabling-compila
'programing' 카테고리의 다른 글
alloca()의 사용은 왜 베스트 프랙티스로 간주되지 않습니까? (0) | 2022.08.30 |
---|---|
마우스 오버 시 Vue 사용자 지정 필터 제거 (0) | 2022.08.30 |
콤마 연산자의 역할은 무엇입니까? (0) | 2022.08.30 |
Vue CDN을 사용할 때 mapGetters를 사용하는 방법 (0) | 2022.08.30 |
프로젝트에서 *plugins*에 대한 Maven 종속성 트리는 어떻게 표시할 수 있습니까? (0) | 2022.08.30 |