문제

C 전처리기는 당연히 두려워하고 기피하여 C++커뮤니티입니다.에서 일렬로 세워지는 기능,consts 와 템플릿은 일반적으로 안전하고 우수한 대안 #define.

다음 macro:

#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)  

에 우수한 안전한 유형:

inline bool succeeded(int hr) { return hr >= 0; }

하지만 매크로가 있는 그들의 장소,주시기 바랍 목록의 사용은 당신이 찾을 위한 매크로는 당신 할 수 없 지 않고는 전처리기.

를 넣어주세요 각 사용-경우에는 별도의 대답할 수 있도록 선정하고 당신의 알을 달성하는 방법 중 하나없이 대답하 preprosessor 점는 방법에는 답변의 의견.

도움이 되었습니까?

해결책

래퍼로에 대한 디버깅 기능,자동으로 통과 같은 것들 __FILE__, __LINE__, 등:

#ifdef ( DEBUG )
#define M_DebugLog( msg )  std::cout << __FILE__ << ":" << __LINE__ << ": " << msg
#else
#define M_DebugLog( msg )
#endif

다른 팁

방법은 항상 완전하고,컴파일할 수 있는 코드매크로될 수 있는 코드 조각이 있습니다.따라서 정의할 수 있습니다 foreach macro:

#define foreach(list, index) for(index = 0; index < list.size(); index++)

으로 그것을 사용하고 따라서:

foreach(cookies, i)
    printf("Cookie: %s", cookies[i]);

이후 C++11,이에 의해 대체 이트에 대한 루프.

헤더 파일의 경비가 필요로 하는 매크로입니다.

은 거기에 다른 어떤 지역 매크로가?많지 않아(있을 경우).

은 거기에 다른 어떤 상황에서는 매크로가?YES!!!

한 곳 내가 사용하는 매크로로 아주 반복되는 코드입니다.예를 들어,감싸는 C++코드를 사용으로 다른 인터페이스(.NET,COM,Python,etc.),나를 잡을 필요가 다른 형식의 예외가 있습니다.여기에 내가 어떻게 그렇게 하도록 요청합니다.

#define HANDLE_EXCEPTIONS \
catch (::mylib::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e); \
} \
catch (::std::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e, __LINE__, __FILE__); \
} \
catch (...) { \
    throw gcnew MyDotNetLib::UnknownException(__LINE__, __FILE__); \
}

나는 이러한 어획량에서 래퍼 기능입니다.보다는 오히려 형식으로 가득 catch 블록을 각각의 시간,나는 단지 유형:

void Foo()
{
    try {
        ::mylib::Foo()
    }
    HANDLE_EXCEPTIONS
}

이것은 또한 유지 보수가 쉽습니다.는 경우가 있을 추가하는 새로운 예외 유형,거기에 하나의 장소가 필요하여 추가합니다.

다른 유용한 예제다:의 많은 것을 포함하는 __FILE____LINE__ 전처리기 매크로입니다.

어쨌든,매크로는 매우 유용한 올바르게 사용하는 경우.매크로를하지 않은 악마의-그들의 오용 한다.

대:

  1. 포함한 경비원
  2. 조건부 편집
  3. 보고(미리 정의된 매크로 처럼 __LINE____FILE__)
  4. (거의)복제 반복되는 코드는 패턴이 있습니다.
  5. 에서 당신의 경쟁자의 코드입니다.

내부 조건 컴파일을 극복하는 문제 사이의 차이점을 컴파일러:

#ifdef ARE_WE_ON_WIN32
#define close(parm1)            _close (parm1)
#define rmdir(parm1)            _rmdir (parm1)
#define mkdir(parm1, parm2)     _mkdir (parm1)
#define access(parm1, parm2)    _access(parm1, parm2)
#define create(parm1, parm2)    _creat (parm1, parm2)
#define unlink(parm1)           _unlink(parm1)
#endif

를 하고자 할 때는 문자열의 표현,최고의 예를 들어 이 assert (#x 회의 값 x 문자열).

#define ASSERT_THROW(condition) \
if (!(condition)) \
     throw std::exception(#condition " is false");

문자열은 상수도 정의된 매크로로 이후의 다양한 작업을 수행할 수 있습니다 문자열보다 const char *.

예:문자열 수 있습니다 쉽게 연결.

#define BASE_HKEY "Software\\Microsoft\\Internet Explorer\\"
// Now we can concat with other literals
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "Settings", &settings);
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "TypedURLs", &URLs);

는 경우 const char * 사용했던 그때 어떤 종류의 문자열 클래스를 사용할을 수행하는 연결한 런타임:

const char* BaseHkey = "Software\\Microsoft\\Internet Explorer\\";
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "Settings").c_str(), &settings);
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "TypedURLs").c_str(), &URLs);

을 변경하려면 프로그램 교류(return, breakcontinue)함수 코드에서와는 다르게 작동합보다는 코드를 실제로 인라인에서는 기능입니다.

#define ASSERT_RETURN(condition, ret_val) \
if (!(condition)) { \
    assert(false && #condition); \
    return ret_val; }

// should really be in a do { } while(false) but that's another discussion.

명 포함한 경비원

#ifndef MYHEADER_H
#define MYHEADER_H

...

#endif

을 수행할 수 없습니다 단락시키는 함수 호출의 인수를 사용하여 정기적인 함수 호출합니다.예를 들어:

#define andm(a, b) (a) && (b)

bool andf(bool a, bool b) { return a && b; }

andm(x, y) // short circuits the operator so if x is false, y would not be evaluated
andf(x, y) // y will always be evaluated

말하자는 무시는 명백한 것과 같은 헤더를 보호합니다.

때때로,당신은 당신이 원하는 코드를 생성해야 하는 복사/붙여 넣으리컴파일러:

#define RAISE_ERROR_STL(p_strMessage)                                          \
do                                                                             \
{                                                                              \
   try                                                                         \
   {                                                                           \
      std::tstringstream strBuffer ;                                           \
      strBuffer << p_strMessage ;                                              \
      strMessage = strBuffer.str() ;                                           \
      raiseSomeAlert(__FILE__, __FUNCSIG__, __LINE__, strBuffer.str().c_str()) \
   }                                                                           \
   catch(...){}                                                                \
   {                                                                           \
   }                                                                           \
}                                                                              \
while(false)

할 수 있는 코드 이:

RAISE_ERROR_STL("Hello... The following values " << i << " and " << j << " are wrong") ;

생성할 수 있습과 같은 메시지:

Error Raised:
====================================
File : MyFile.cpp, line 225
Function : MyFunction(int, double)
Message : "Hello... The following values 23 and 12 are wrong"

참고로 섞는 템플릿과 매크로로 이어질 수 있는 더 나은 결과물(예:자동으로 생성하는 값 side-by-side 과 그들의 변수 이름)

다른 시간에,당신은 필요합__파일______________이며 또__선__의 일부 코드를 생성하는 디버깅 정보,예를 들어.다음과 같은 고전적인 Visual C++:

#define WRNG_PRIVATE_STR2(z) #z
#define WRNG_PRIVATE_STR1(x) WRNG_PRIVATE_STR2(x)
#define WRNG __FILE__ "("WRNG_PRIVATE_STR1(__LINE__)") : ------------ : "

으로 다음과 같은 코드:

#pragma message(WRNG "Hello World")

그것은 메시지를 생성 다음과 같:

C:\my_project\my_cpp_file.cpp (225) : ------------ Hello World

다른 시간에,당신은 필요를 생성하는 코드를 사용하여#고##연결 연산자,처럼 생성현한 속성(이것은 아주 제한된 경우,이를 통해).

다른 시간에,당신은 코드를 생성보다 못할 경우 컴파일에 사용을 통해 기능,다음과 같:

#define MY_TRY      try{
#define MY_CATCH    } catch(...) {
#define MY_END_TRY  }

으로 사용될 수 있는

MY_TRY
   doSomethingDangerous() ;
MY_CATCH
   tryToRecoverEvenWithoutMeaningfullInfo() ;
   damnThoseMacros() ;
MY_END_TRY

(여전히,나는 나만 보는 이런 종류의 코드에 바로 사용되는 )

마지막으로,그러나,유명한 boost::foreach !!!

#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );

    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}

(주의:코드는 복사/붙여서는 부스트 홈페이지)

는(IMHO)보다 더 나은 방법 std::for_each.

그래서,매크로를 항상이 유용하기 때문에 그들은 외부의 정상적인 컴파일러는 규칙이 있습니다.그러나 나는 대부분의 시간이 나는 하나,그들은 효율적으로 유의 C 코드 적으로 번역 적절한 C++.

단위 테스트 프레임워크를 위한 C++같은 Unittest 에 대한 여러++ 꽤 많은 주위에 회귀한 전처리기 매크로입니다.몇 줄의 단위 테스트 코드로 확장 클래스의 계층구조지 않는 것에 재미를 모두 입력 할 수 있습니다.지 않고 같은 것 unittest 에 대한 여러++고 그것의 전처리기 매직,내가 알지 못하는 방법 당신이 효율적으로 작성 단위 테스트를 위한 C++.

을 두려워 C 전처리기는 것 같은 두려워하는 백열 전구 때문에 우리는 형광 램프를 통해 가능합니다.예,이전이 될 수 있습{전기|프로그래머시}비효율적이다.예,당신이 얻을 수 있습니다(문자)에 의해 불니다.하지만 그들은 작업을 수행할 경우 제대로 처리합니다.

프로그래밍할 때 임베디드 시스템,C 사용하는 옵션만 떨어져 형태 assembler.후 프로그래밍 데스크톱에서는 C++로 전환하는 작은,내장 된 대상 당신 배우 중지에 대한 걱정"inelegancies"이렇게 많은 벌거벗은 C 기능(매크로를 포함)및 노력하는 그 밖으로 가장 안전한 사용에서 얻을 수 있는 기능.

Stepanov 는 알렉산더 :

때 우리는 프로그램에서는 C++우리는 부끄러워하지 않아도 되는 그것의 C 문화 유산,그러나 확인 의 전체를 사용니다.만 문제는 C++,심지만 문제는 C,이 발생할 때 그들은 자신이 일정하지 않으로 자신의 논리입니다.

우리가 사용하는 __FILE____LINE__ 매크로 진단하기 위해서 풍부한 정보는 예외를 던지는,잡고 및 로깅과 함께,자동화 로그 파일 스캐너에서 우리의 QA infrastructure.

예를 들어,던지는 매크로 OUR_OWN_THROW 사용될 수 있습으로 예외를 입력 및 생성자를 위한 매개 변수는 예외를 포함하여 텍스트로 설명이 있습니다.다음과 같다:

OUR_OWN_THROW(InvalidOperationException, (L"Uninitialized foo!"));

이 매크로는 것입니다 물론을 던져 InvalidOperationException 예외적으로 설명으로 생성자를 매개 변수이지만,그것은 또한 메시지를 작성하는 로그 파일의 구성된 파일의 이름과 줄번호를 던져 발생하고 해당 설명 텍스트.발생한 예외를 얻을 것이다 id,또한 기록합니다.의 경우에는 예외로 지금까지 잡은 다른 곳에서 코드,그것은 같은 표시 될 것입 및 로그 파일을 다음을 나타내는 특정 예외로 취급되었다는 것과 그러므로 가지 않을 가능성이 원하는 모든 충돌 기록될 수 있습니다.처리되지 않은 예외로 쉽게 선택할 수 있습까지 우리 자동 QA infrastructure.

코드 반복합니다.

후원 전처리기는 라이브러리,그것의 종류의 meta-meta-프로그래밍입니다.에서 주제->동기 부여 찾을 수 있습니다 좋은 예입니다.

일부 매우 유용한 고급건 수 있는 여전히 사용되는 전처리기(매크로),는 것을 할 수 없을 사용하여 c++"어 구성 포함하여"템플릿이 있습니다.

예제:

무언가를 만들기 모두 C 식별자와 문자열

쉬운 방법으로 변수를 사용하여 열거의 형식 문자열로에서 C

후원 전처리기는 메타 프로그래밍

나는 가끔 매크로를 사용하여할 수 있도록 정의하는 정보가 한 장소에서 사용 하지만 다른 방법으로 그것의 다른 부분에 코드입니다.그것은 약간만 악:)

예를 들어,"field_list.h":

/*
 * List of fields, names and values.
 */
FIELD(EXAMPLE1, "first example", 10)
FIELD(EXAMPLE2, "second example", 96)
FIELD(ANOTHER, "more stuff", 32)
...
#undef FIELD

그런 다음에 대한 공개 열거할 수 있을 정의하는 그 이름을 사용:

#define FIELD(name, desc, value) FIELD_ ## name,

typedef field_ {

#include "field_list.h"

    FIELD_MAX

} field_en;

와에서 개인 init 기능을 모두 필드를 채우는 데 사용할 수 있는 테이블과 데이터:

#define FIELD(name, desc, value) \
    table[FIELD_ ## name].desc = desc; \
    table[FIELD_ ## name].value = value;

#include "field_list.h"

한 가지 일반적인 사용이 검출을 위한 컴파일 환경을 위한 크로스-플랫폼을 개발할 수 있습니다.의 설정 코드에 대한 리눅스,말,그리고 다른 윈도우 없을 때 플랫폼에 라이브러리 이미 존재한 당신의 목적이다.

그래서,거친 예 크로스-플랫폼 수 있는 mutex

void lock()
{
    #ifdef WIN32
    EnterCriticalSection(...)
    #endif
    #ifdef POSIX
    pthread_mutex_lock(...)
    #endif
}

는 기능을 위해,그들은 유용하고 싶을 때 명시적으로 무시하는 형식의 안전성이 낮아집니다.등 많은 예 위와 아래에 대한 하 ASSERT.물론,같은 많은 C/C++기능을 촬영할 수 있습에 자신을 발하지만,언어 당신에게 도구를 제공합할 수 있습 무엇을 할 수 있습니다.

뭔가

void debugAssert(bool val, const char* file, int lineNumber);
#define assert(x) debugAssert(x,__FILE__,__LINE__);

할 수 있도록 예를 들어 단지

assert(n == true);

와 소스 파일명과 줄번호 문제의 인쇄의 경우 로그 n 은 거짓입니다.

당신이 사용하는 경우 정상적인 함수 호출에 등

void assert(bool val);

신의 매크로,모든 당신을 얻을 수 있다는 당신의 주장하는 함수의 라인 번호에 의하여 인쇄되는 로그에는 적은 것이 유용합니다.

#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])

과는 달리'기본'템플릿 솔루션을 논의에서는 현재 스레드를 사용할 수 있습으로 그것을 일정한 표현:

char src[23];
int dest[ARRAY_SIZE(src)];

당신이 사용할 수 있습#정의 도움으로 디버깅 및 유닛 테스트 시나리오.예를 들어,특별한 로깅 개의 메모리 기능과 특별한 만든 memlog_preinclude.h:

#define malloc memlog_malloc
#define calloc memlog calloc
#define free memlog_free

컴파일을 사용하여 코드:

gcc -Imemlog_preinclude.h ...

링크에서 당신의 memlog.o 최종 이미지입니다.당신은 지금 제어 malloc,etc.,아마도 로깅을 위해서,또는 시뮬레이션 할당 오류에 대한 단위 테스트를 확인할 수 있습니다

내가 사용하는 매크로를 쉽게 예외를 정의:

DEF_EXCEPTION(RessourceNotFound, "Ressource not found")

는 DEF_EXCEPTION 가

#define DEF_EXCEPTION(A, B) class A : public exception\
  {\
  public:\
    virtual const char* what() const throw()\
    {\
      return B;\
    };\
  }\

컴파일러를 거부할 수 있습 귀하의 요청하는 인라인 요소입니다.

매크로를 항상 있을 것이다 그들의 장소입니다.

내가 찾는 것은#정의한 디버깅을 위해 디버깅 tracing-당신이 그것을 남길 수 있습니다 1 동안 문제를 디버깅(또는 그 중에 전체적인 개발 사이클)로 시간입니다.

할 때 의사 결정에서 컴파일 시간 이상의 컴파일러/OS/하드웨어 특정한 행동입니다.

그것은 당신을 당신의 인터페이스를 Comppiler/OS/하드웨어 특정 기능을 갖추고 있습니다.

#if defined(MY_OS1) && defined(MY_HARDWARE1)
#define   MY_ACTION(a,b,c)      doSothing_OS1HW1(a,b,c);}
#elif define(MY_OS1) && defined(MY_HARDWARE2)
#define   MY_ACTION(a,b,c)      doSomthing_OS1HW2(a,b,c);}
#elif define(MY_SUPER_OS)
          /* On this hardware it is a null operation */
#define   MY_ACTION(a,b,c)
#else
#error  "PLEASE DEFINE MY_ACTION() for this Compiler/OS/HArdware configuration"
#endif

에서 마지막 작업,작업을했 바이러스 스캐너입니다.을 위해 일을 더 쉽게 디버깅,저는 많은 이야기를 했어 로깅 붙어 모든 장소,하지만 높은 수요 같은 응용 프로그램,의 비용 함수 호출에는 너무 비싸다.그래서 나는 이 작은 매크로는 여전히 나를 사용하려면 디버그에 로그온 릴리스 버전에서는 고객 사이트,비용없이의 함수를 호출 확인하는 디버그 국기와 그냥 돌아 로그인하지 않고 아무거나,또는 사용하는 경우,할 것은 로깅...매크로가의 정의는 다음과 같습니다.

#define dbgmsg(_FORMAT, ...)  if((debugmsg_flag  & 0x00000001) || (debugmsg_flag & 0x80000000))     { log_dbgmsg(_FORMAT, __VA_ARGS__);  }

기 때문에 VA_ARGS 에서는 로그 기능,이것이 좋은 사례에 대한 매크로를 이렇습니다.

기 전에는,내가 사용하는 매크로에서 높은 보안 응용 프로그램을 필요로하는 사용자에게 그들이 가지고 있지 않은 올바른 액세스,그리고 그것은 그들에게 어떤 플래그 그들이 필요합니다.

매크로(s)로 정의된다:

#define SECURITY_CHECK(lRequiredSecRoles) if(!DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, true)) return
#define SECURITY_CHECK_QUIET(lRequiredSecRoles) (DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, false))

그러면 우리는 그냥 뿌리 검사를 통해 모든 UI,그리고 그것은 말할 것 역할을 수행하도록 허용된 작업을 시도하지 않았으면 이미하는 역할입니다.이유가 그 두었는 값을 반환하기 위해 어떤 장소에서 돌아와에서 무효화 기능을 다른 사람에...

SECURITY_CHECK(ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR);

LRESULT CAddPerson1::OnWizardNext() 
{
   if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_EMPLOYEE) {
      SECURITY_CHECK(ROLE_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD ) -1;
   } else if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_CONTINGENT) {
      SECURITY_CHECK(ROLE_CONTINGENT_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR) -1;
   }
...

어쨌든,어떻게 사용했던 그들이,그리고 나는 확실하지 않는 방법이 도움이 되었습니다와 함께 템플릿을...다른 것보다,나는 그들을 피하기 위해 시도하지 않으면 정말 필요합니다.

아직 다른 foreach macros.T:유형 c:컨테이너,내가:반복기

#define foreach(T, c, i) for(T::iterator i=(c).begin(); i!=(c).end(); ++i)
#define foreach_const(T, c, i) for(T::const_iterator i=(c).begin(); i!=(c).end(); ++i)

사용량(보여주는 개념,진짜):

void MultiplyEveryElementInList(std::list<int>& ints, int mul)
{
    foreach(std::list<int>, ints, i)
        (*i) *= mul;
}

int GetSumOfList(const std::list<int>& ints)
{
    int ret = 0;
    foreach_const(std::list<int>, ints, i)
        ret += *i;
    return ret;
}

더 구현이 가능합니다:Google "BOOST_FOREACH"

좋은 기사를 사용: 조건적인 사랑:FOREACH 돌아 (Eric Niebler) http://www.artima.com/cppsource/foreach.html

어쩌면 가장 훌륭한 사용법의 매크로에 플랫폼-독립적인 개발.에 대해 생각의 경우 형식의 불일치-매크로,당신은 단순히 다른 사용 헤더 파일을 같이--:--WIN_TYPES.H

typedef ...some struct

--POSIX_TYPES.h

typedef ...some another struct

--프로그램입니다.h

#ifdef WIN32
#define TYPES_H "WINTYPES.H"
#else 
#define TYPES_H "POSIX_TYPES.H"
#endif

#include TYPES_H

훨씬 읽을 수 있을 구현하는 것보다 그것은 다른 방법으로 나의 의견입니다.

보 VA_ARGS 만 있을 언급되는 간접적으로 지금까지:

을 작성할 때 일반적인 C++코드 03,당신은 필요한 변수의 번호(generic)매개 변수를 사용할 수 있습니다,매크로로 대신합니다.

#define CALL_RETURN_WRAPPER(FnType, FName, ...)          \
  if( FnType theFunction = get_op_from_name(FName) ) {   \
    return theFunction(__VA_ARGS__);                     \
  } else {                                               \
    throw invalid_function_name(FName);                  \
  }                                                      \
/**/

참고: 에서 일반적인 이름은 체크인/을 던질 수 있습으로 통합된 가상의 get_op_from_name 기능입니다.이것은 단지 예입니다.될 수 있습 다른 일반적인 코드 주변 VA_ARGS 호출합니다.

일단 우리가 앞으로 C++11,우리는 우리를 해결할 수 있습이"제대로"가 있습니다.

나는 생각이 트릭은 영리한 사용 전처리기할 수 없는 에뮬레이트와 기능:

#define COMMENT COMMENT_SLASH(/)
#define COMMENT_SLASH(s) /##s

#if defined _DEBUG
#define DEBUG_ONLY
#else
#define DEBUG_ONLY COMMENT
#endif

다음과 같이 사용할 수 있습 this:

cout <<"Hello, World!" <<endl;
DEBUG_ONLY cout <<"This is outputed only in debug mode" <<endl;

를 정의할 수도 있습 RELEASE_ONLY 매크로입니다.

#define 상수에 컴파일러를 사용하여 명령줄 -D/D 옵션입니다.이것은 자주 유용하면 크로스 컴파일하는 동일한 소프트웨어에 대한 여러 플랫폼 수 있기 때문에 당신이 당신의 제어 메이크 어떤 상수 정의에 대한 각 플랫폼입니다.

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