2014-12-22 2 views
0

최근에 gflags의 소스 코드를 읽었습니다. 그리고 여기의 코멘트는 정말로 나를 혼란스럽게합니다.FLAGS_nono의 사용 ## name in gflags 소스 코드

정적 초기화를 보장하기 위해 FLAGS_nono ## name이 도입되었습니다. 그러나 내가 아는 한, 전역 변수를 다음과 같이 정의한다면 : int x = 20;

x 여전히 정적으로 초기화됩니다. FLAGS_nono ## name의 필요성은 무엇입니까?

오해할까요?

감사합니다.

// Each command-line flag has two variables associated with it: one 
// with the current value, and one with the default value. However, 
// we have a third variable, which is where value is assigned; it's a 
// constant. This guarantees that FLAG_##value is initialized at 
// static initialization time (e.g. before program-start) rather than 
// than global construction time (which is after program-start but 
// before main), at least when 'value' is a compile-time constant. We 
// use a small trick for the "default value" variable, and call it 
// FLAGS_no<name>. This serves the second purpose of assuring a 
// compile error if someone tries to define a flag named no<name> 
// which is illegal (--foo and --nofoo both affect the "foo" flag). 
#define DEFINE_VARIABLE(type, shorttype, name, value, help)    \ 
    namespace fL##shorttype {            \ 
    static const type FLAGS_nono##name = value;       \ 
    /* We always want to export defined variables, dll or no */   \ 
    GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = FLAGS_nono##name;  \ 
    type FLAGS_no##name = FLAGS_nono##name;        \ 
    static @[email protected]::FlagRegisterer o_##name(\ 
     #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__,    \ 
     &FLAGS_##name, &FLAGS_no##name);         \ 
    }                  \ 
    using fL##shorttype::FLAGS_##name 

더 컨텍스트를 들어, https://code.google.com/p/gflags/source/browse/src/gflags.h.in#471

을 또 다른 문제는 위에서 언급 한 코드에 사용 된 FlagRegisterer 클래스입니다 참조하십시오. 간단히 함수를 정의하는 대신 클래스와 전역 var의 필요성에 대해 궁금합니다.

class GFLAGS_DLL_DECL FlagRegisterer { 
public: 
    FlagRegisterer(const char* name, const char* type, 
       const char* help, const char* filename, 
       void* current_storage, void* defvalue_storage); 
}; 


// -------------------------------------------------------------------- 
// FlagRegisterer 
// This class exists merely to have a global constructor (the 
// kind that runs before main(), that goes an initializes each 
// flag that's been declared. Note that it's very important we 
// don't have a destructor that deletes flag_, because that would 
// cause us to delete current_storage/defvalue_storage as well, 
// which can cause a crash if anything tries to access the flag 
// values in a global destructor. 
// -------------------------------------------------------------------- 

FlagRegisterer::FlagRegisterer(const char* name, const char* type, 
           const char* help, const char* filename, 
           void* current_storage, void* defvalue_storage) { 
    if (help == NULL) 
    help = ""; 
    // FlagValue expects the type-name to not include any namespace 
    // components, so we get rid of those, if any. 
    if (strchr(type, ':')) 
    type = strrchr(type, ':') + 1; 
    FlagValue* current = new FlagValue(current_storage, type, false); 
    FlagValue* defvalue = new FlagValue(defvalue_storage, type, false); 
    // Importantly, flag_ will never be deleted, so storage is always good. 
    CommandLineFlag* flag = new CommandLineFlag(name, help, filename, 
               current, defvalue); 
    FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry 
} 

답변

0

int i = 10;과 같은 것으로 정적 초기화가 수행됩니다. 따라서 쓰기가 가능합니다.

#define DEFINE_VARIABLE(type, shorttype, name, value, help)    \ 
    namespace fL##shorttype {            \ 
    /* We always want to export defined variables, dll or no */   \ 
    GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = value;     \ 
    type FLAGS_no##name = value;          \ 
    static @[email protected]::FlagRegisterer o_##name(\ 
     #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__,    \ 
     &FLAGS_##name, &FLAGS_no##name);         \ 
    }                  \ 
    using fL##shorttype::FLAGS_##name 

그러나이 매크로는주의해야합니다. value에 대한 여러 참조로 인해 여러 확장이 발생합니다. value이 아니고, 상수가 아닌 인 경우, 예를 들어. 함수 호출로 인해 함수가 두 번 호출됩니다. 다른 하나 개의 변수를 복사하여 피할 수

:

#define DEFINE_VARIABLE(type, shorttype, name, value, help)    \ 
    namespace fL##shorttype {            \ 
    /* We always want to export defined variables, dll or no */   \ 
    GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = value;     \ 
    type FLAGS_no##name = FLAGS_##name;         \ 
    static @[email protected]::FlagRegisterer o_##name(\ 
     #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__,    \ 
     &FLAGS_##name, &FLAGS_no##name);         \ 
    }                  \ 
    using fL##shorttype::FLAGS_##name 

하지만 지금 당신은 당신이 정적 초기화를 원하는 것 동적 초기화를 가지고있다.

제대로 작동하는지 확인하려면 추가 도우미 변수가 필요하며 그 코드가 요구하는 것입니다.