2012-07-04 6 views
1

매크로와 가독성에 대한 논쟁이있었습니다. 매크로를 사용하는 경우 코드를 더 짧고 이해하기 쉬우 며 읽기 어려워 질 수도 있습니다. 예를 들어매크로를 사용하면 코드를 읽기 쉽도록 만들 수 있습니까?

:이 짧고 컴팩트하고 뚜껑이 텍스트는 단지 명확하고 낙타의 경우보다 쉽게 ​​읽을 수 잠금 때문에

#include <iostream> 

#define EXIT_ON_FAILURE(s) if(s != 0) {std::cout << "Exited on line " << __LINE__ << std::endl; exit(1);} 

inline void exitOnFailure(int s, int lineNum) { 
    if (s != 0) { 
     std::cout << "Exited on line " << lineNum << std::endl; 
     exit(1); 
    } 
} 

int foo() { 
    return 1; 
} 

int bar(int a, int b, int c) { 
    return 0; 
} 

int main() { 
    // first option 
    if (foo() != 0) { 
     std::cout << "Exited on line " << __LINE__ << std::endl; 
     exit(1);  
    } 
    if (bar(1, 2, 3) != 0) { 
     std::cout << "Exited on line " << __LINE__ << std::endl; 
     exit(1);  
    } 

    // second option 
    EXIT_ON_FAILURE(foo()); 
    EXIT_ON_FAILURE(bar(1, 2, 3)); 

    // third option 
    exitOnFailure(foo(), __LINE__); 
    exitOnFailure(bar(1, 2, 3), __LINE__); 

    return 0; 
} 

나는 여기에 두 번째 옵션을 선호합니다.

이 방법에 문제가 있습니까? 특히 C++에서 문제가 있습니까? 또는 좋지 않지만 받아 들일 수있는 스타일입니까?

+0

나는 매크로를 사용하는 것이 대부분의 경우 좋지 않다고 생각한다. 세 번째 옵션이 더 좋습니다. –

+3

'__LINE__'을 넘긴다면 함수로도 같은 일을 할 수 있습니다. – chris

+0

@AdityaKumar : 세 번째 옵션을 제외하고는 유용한 행 번호가 제공되지 않습니다. 그것이 (때때로) 매크로를 사용하는 좋은 이유 중 하나입니다. –

답변

3

매크로는 C/C++의 매우 강력한 기능이며 기본적으로 모든 C 기능 ( )이 발로 지정되어 있습니다. 문에서 if 또는 EXIT_ON_FAILURE를 확장하여 만든 if

if (doSomething()) 
    EXIT_ON_FAILURE(s) /* <-- MISSING SEMICOLON! OH NOES!!! */ 
else 
    doSomethingElse(); 

else이 속한 않습니다 매크로의 다음 사용을 고려? 어쨌든 하나의 누락 된 세미콜론의 동작은 전혀 예상치 못한 결과입니다. EXIT_ON_FAILURE() 이 함수 인 경우 컴파일러 오류가 발생합니다. 이 경우에는 컴파일하지만 잘못된 것을 수행하는 코드는 입니다.

매크로에 문제가 있습니다. 함수 또는 변수처럼 보이지만 이 아닙니다. 잘못 쓰여진 매크로는 이주는 선물입니다. 매크로를 사용할 때마다 잠재적 인 미묘한 버그가 발생할 수 있으며 매크로를 변경할 때마다 논리 오류를 코드 에 건 드리면 사용자가 만지지 않았다고 위협 할 수 있습니다.

일반적으로 꼭 필요한 경우가 아니라면 매크로를 피해야합니다.

상수를 정의해야하는 경우 const 변수 또는 enum을 사용하십시오. 좋은 컴파일러 (무료로 얻을 수 있음)는 #define 상수 처럼 결과 실행 파일에 리터럴로 바꿀 것입니다.하지만 예상대로 사용자 정의 변환을 처리하고 디버거에 이 표시됩니다 기호 테이블입니다.

인라인 함수와 같은 것이 필요한 경우 인라인 함수를 사용하십시오. C++과 C99 둘 다 제공하며 대부분 무료 컴파일러 (예 : 비어있는 컴파일러)는 오랫동안 확장자로 사용했습니다.

함수는 인수가 매크로 달리 평가 될, 그래서

#define DOUBLE(a) (a + a) 

두 번 a을 평가하는 반면

inline int DOUBLE(int a) {return a+a;} 

은 오직 한 번 a을 평가합니다 강제로. 즉, DOUBLE이 함수 인 경우보다 매크로 인 경우

x = DOUBLE(someVeryLongFunction()); 

이 두 배 오래 걸립니다.

DOUBLE(a << b) 

이 완전히 놀라운 결과를 줄 것이다 :

또한, 나는 (의도적으로) 이 매크로 인수를 괄호로 깜빡 때문에. 은 즉

#define DOUBLE(a) ((a) + (a)) 

로 DOUBLE 매크로를 작성하는 기억해야 할 것입니다, 당신은 완벽 단지에 매크로를 작성 발에서 자신을 촬영 가능성을 최소화 할 필요가있다. 실수하면 실수로 을 지불하게됩니다.

모두 그렇습니다. 입니다. 매크로를 사용하면 코드 이 더 읽기 쉽습니다. 그들은 거의없고 그 사이에 있지만 그들은 존재합니다. 그 중 하나는 코드가 다시 작성되는 assert 매크로입니다. 복잡한 시스템은 로컬 디버깅 방식으로 묶어 assert -like 매크로 자신의 정의를 사용하는 것은 매우 흔한 일, 그 거의 항상, __FILE__에서 __LINE__ 및 조건의 텍스트를 얻기 위해 매크로로 구현된다.

는하지만 그렇다하더라도, 이것은 전형적인 assert이 구현되는 방법이다 : 즉

#ifdef NDEBUG 
# define assert(cond) 
#else 
# define assert(cond) __assert(cond, __FILE__, __LINE__, #cond) 
#endif 

은 함수와 같은 매크로는 함수 호출로 확장합니다. 이 방법을 사용하면 assert을 호출 할 때 확장이 거의 비슷해 보이며 인수 확장이 과 같은 방식으로 이루어 지므로 확장이 여전히 매우 비슷합니다. .

그리고 몇 가지 다른 용도가 있습니다.기본적으로 언제든지 프로세스 자체에서 프로그램에 정보를 전달해야하므로 은 아마 매크로 시스템을 통과해야합니다. 그럼에도 불구하고 은 매크로에 닿는 코드의 양을 최소화해야하며 매크로의 영향을 최소화해야합니다.

마지막으로 한 가지. 코드가 더 빠를 것이라고 생각하여 매크로를 사용하고 싶다면 악마가 말하는 것을 알아야합니다. 에서 예전에는 작은 매크로를 매크로로 변환하면 눈에 띄게 성능이 향상되는 경우가있었습니다. 이 일 비록 :

  1. 대부분의 컴파일러는 인라인 기능을 지원합니다. 심지어 일부는 정적 함수에 을 자동으로 수행합니다.

  2. 현대 컴퓨터는 너무 빠르기 때문에 거의 기능을 호출하지 않는 오버 헤드가 있음을 거의 인식하지 못합니다.

인라인 함수 을하고하지 않는 컴파일러는 그냥 더 나은 하나 과로 교체 할 수없는 경우에만 당신은 오버 헤드를 호출 기능 입증은 병목 수 있습니다했습니다 당신은 아마 몇 가지 매크로 작성을 정당화 할 수 있습니다.

아마도.

+0

+1 "코드가 더 빨라지므로 매크로를 사용하고 싶다면 악마가 말하는 것을 알아 두십시오." 조기에 최적화하면 [히틀러와 함께 최적화!] (http://en.wikipedia.org/wiki/File:Ride_with_hitler.jpg) –

+0

위대한 답변! 특히 좋은 매크로 사용 예 (디버그 어설 션). – Cade

0

확실한 매크로는 기능을 단순화하여 읽기 쉽게 만듭니다. 그러나 인라인 함수를 대신 사용해보십시오.

예에서 EXIT_ON_FAILURE는 인라인 함수가 될 수 있습니다. 하나는 기대할 수 있지만

#define MY_MACRO(s) if (s * 2 >= 20) foo() 

// later on your code: 
MY_MACRO(5 + 5); 

: 매크로 다만, 특별히 변수를 매크로를 사용할 때주의해야 할 몇 가지가있다, (그것이 어떤하는 오류는 잘못된 장소에 표시 될 수 있습니다) 부정확 한 컴파일러하는 오류를하지,이 예제를 고려 foo()를 호출하면 if (10 * 2 >= 20) foo()으로 확장되지 않으므로 if (5 + 5 * 2 >= 20) foo()으로 확장됩니다. 따라서 매크로를 정의 할 때는 항상 변수 주위에()를 사용하는 것을 기억해야합니다.

매크로는 또한 프로그램을 디버그하기가 어렵게 만듭니다.

0

매크로가 필요할 때가 있지만 매크로의 수를 최소화해야합니다. 귀하의 예제에서, 이미 "assert"라는 매크로가 있습니다.이 매크로는 새 매크로를 만드는 대신 사용할 수 있습니다.

C++에는 C에서 매크로가 필요한 매크로없이 작업을 수행 할 수있는 많은 기능이 있으므로 매크로는 C 코드에서보다 C++ 코드에서 훨씬 덜 일반적입니다.

+0

사용자를 놀라게 할 수 있으므로 어설 션을 사용하고 싶지 않은 경우가 있습니다. 이러한 경우 유익한 결과물이 더 나을 수 있습니다. –

+0

@WhiteZebra 무엇에 대해 두려워해야합니까? 주장 뒤에있는 아이디어는 소프트웨어가 출시되기 전에 예방 가능한 문제를 찾기 위해 디버그 빌드에 사용하는 것입니다. 그 이유 때문에 assert-macro는 릴리즈 모드에서 아무런 동작도하지 않게 정의됩니다 (http://en.cppreference.com/w/cpp/error/assert 참조) ... – MFH

관련 문제