2013-02-13 4 views
7

私はopensourceプロジェクトのコードサンプルを参照していますtigどちらが素晴らしいツールです!マクロでEnum/Structを定義する必要はありますか?

ファイル:tig.c私は次のように要求列挙を定義するための理由を見つけるのに苦労しています

enum request { 
#define REQ_GROUP(help) 
#define REQ_(req, help) REQ_##req 

     /* Offset all requests to avoid conflicts with ncurses getch values. */ 
     REQ_UNKNOWN = KEY_MAX + 1, 
     REQ_OFFSET, 
     REQ_INFO, 

     /* Internal requests. */ 
     REQ_JUMP_COMMIT, 

#undef REQ_GROUP 
#undef REQ_ 
}; 

さえ構造を、同様..

static const struct request_info req_info[] = { 
#define REQ_GROUP(help) { 0, NULL, 0, (help) }, 
#define REQ_(req, help) { REQ_##req, (#req), STRING_SIZE(#req), (help) } 
     REQ_INFO 
#undef REQ_GROUP 
#undef REQ_ 
}; 

見ることができるようにREQ_GROUPは複数回#定義されています。よく私はそのような理由があるかもしれないことを知っている..マクロを使用してコード内の列挙体/構造体の定義を隠す実際の理由は何ですか?

+2

何が起こっているのか理解するために、前処理されたソースとなるgccオプション '-dNI -E'を使ってソースをコンパイルすると便利ですが、マクロは展開されずに'#include'文はそのままです。 –

+1

以下の答えがあります。この戦略の一般的な名前は "Xマクロ"、ウィキペディアにはそのページがあります:http://en.wikipedia.org/wiki/X_Macro Dr Dobbsも同様です:http://www.drdobbs.com/cpp/the -x-macro/228700289 – Vicky

+0

@Vicky drdobbsリンクは宝石でした!ありがとう! – ashishsony

答えて

7

同じデータソースで異なる治療法を使用する必要がある場合は、通常これがダウンします。

たとえば、あなたが行う可能性があります。その後、

#define MY_LIST X(Elem1) X(Elem2) X(Elem3) 

とを:

enum MyEnum { 
# define X(e) e, 

    MY_LIST 

    Last 

# undef X 
}; 

その場合には、MY_LISTX現在定義を使用して展開されています。

今、同じファイルで、私も

char const* to_string(MyEnum e) { 
    switch(e) { 
#  define X(e) case e: return #e; 

     MY_LIST 

     case Last: return "Last"; 

#  undef X 
    } 
    return 0; 
} // to_string 

をこのようにto_stringメソッドを作成するMY_LISTを使用することができ、列挙型の値のセットのみ、これまで一度書き込まれ、自動的に両方の列挙型とそれを扱ういくつかのメソッドがこのセットと同期して保持されます。

1

リクエストリストの重複を避けるためです。そのリストは、1つの場所で維持する必要があり、定義はREQ_INFOであり、列挙およびデータ構造はREQ_GROUPおよびREQ_という適切な定義によってそのリストから自動的に生成されます。

これらのマクロを使用しないと、列挙型とデータ構造は、相互に一貫性を維持しながら、より多くの作業とエラーの範囲を含むように注意して別々に管理する必要があります。

#define REQ_INFO \ 
REQ_GROUP("View switching") \ 
VIEW_INFO(VIEW_REQ), \ 
\ 
REQ_GROUP("View manipulation") \ 
REQ_(ENTER, "Enter current line and scroll"), \ 
REQ_(NEXT, "Move to next"), \ 
REQ_(PREVIOUS, "Move to previous"), \ 
< output omitted as it is too long > 

だから、例えば、あなたが示されている構造はに展開:

1

あなたが同じファイル内の重要な定義見逃している他の回答が述べたように

static const struct request_info req_info[] = { 
    { 0, NULL, 0, "View switching" }, 
    < VIEW_INFO also expands to some long structure that was ommited here > 
    { 0, NULL, 0, "View manipulation" }, 
    { REQ_ENTER, ENTER, STRING_SIZE("ENTER"), "Enter current line and scroll"}, 
    { REQ_NEXT, NEXT, STRING_SIZE("NEXT"), "Move to next"} 
    < and so on > 
}; 

を、それが主に行われています複数の構造体/列挙子を同期させておく。

関連する問題