c言語マクロ定義(macro)学習

4249 ワード

参照先:https://gcc.gnu.org/onlinedocs/cpp/Macros.html
gccコンパイルプロセスは一般的に前処理,コンパイル,アセンブリ,接続の4段階に分けられる.マクロ定義は、前処理フェーズで展開されます.プリプロセッサはc予約キーワードを認識していないため、ほとんどの合法的な識別子をマクロとして定義することができます.例えば、constの意味を再定義することができます.defineキーとc++ネーミングオペレータのみが再定義できません.
一.オブジェクト形式のマクロ定義:#define OBJECT_MACRO macro-body
特に、マクロ定義は呼び出しポイントでそのまま展開され、通常の関数とは異なることに注意してください.たとえば、次のコード・セグメントがあります.
#define THREE 1+2
std::cout<>>output:5

出力結果は5であり,我々の期待と一致しなかった.この点を解決するのも簡単です.
#define THREE (1+2)
std::cout<>>output:6

二.関数形式のマクロ定義:#define FUNC_MACRO(param1,param2,...,paramn) macro-body
FUNC_MACROは関数のように呼び出され、パラメータは呼び出されたときにそのまま展開されます.マクロ名と()の間にスペースがないことに注意してください.そうしないとOJBECT_と見なされます.MACRO展開.
マクロ定義に同じ名前のマクロ定義が表示されている場合は、展開されません.そうしないと、無限に再帰されます.この特性を利用することができますたとえば、次のコードがあります.
#define printf(fmt, args...) \
printf(fmt, ##args); \
printf(", world
") int main(){ printf("hello"); } >>>output:hello,world

三.マクロ関数のパラメータを文字列に変換(#)
マクロ関数パラメータの前に#番号を付けると、このパラメータは展開されず、そのまま文字列形式に置き換えられます.たとえば、次のコードがあります.
#define WARN_IF(EXP) \
do { if (EXP) \ 
       fprintf (stderr, "Warning: " #EXP "
"); } \ while (0) WARN_IF (x == 0); >>>output: Warning:x == 0

四.接続記号(##)
##2つのシンボルを接続できます.マクロ関数パラメータであれば、マクロ関数パラメータが展開されます.例:
#define CONCAT(p1, p2)   p1 ## _ ## p2
int  CONCAT(hello,world) = 10;
>>>  : int hello_world = 10;

五.変長パラメータ(...)
マクロ定義には、2つの方法で変長パラメータを処理します.
#define eprintf( ...) printf(__VA_ARGS__)
#define eprintf( arg...) printf( arg)

より読みやすさを向上させるために、上記の関数を次のフォーマットとして定義することがあります.
#define eprintf(format, ...) printf(format, __VA_ARGS__)
#define eprintf(format, arg...) printf(format, arg)

このように定義すると、可変パラメータのリストが空の場合、マクロ定義が展開されるとカンマ(,)が1つ増えるという問題があります.
GNU CPPは、可変パラメータの前に##を加算するソリューションをそれぞれ示しており、コードは以下の通りである.
#define eprintf(format, ...) printf(format , ##__VA_ARGS__)
#define eprintf(format, arg...) printf(format,  ##arg)

六.定義済みマクロ変数:
6.1標準定義マクロ変数.
言語仕様では、すべてのコンパイラがサポートされています.
__FILE__ :現在のファイル名
__LINE__ :現在の行番号
__cplusplus:c++コンパイラの場合、このマクロは定義されます.そうしないと定義されません.
6.2汎用事前定義マクロ
GNU C extensionsによって定義されます.GNU Cを使うと、彼らの意味は同じです.
__COUNTER__ :単調にインクリメントされたカウンタで、最初の使用値は0で、2回目は1です...
_GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__
gnucのバージョンを検出します.たとえば、次のコードがあります.
#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100 \
                     + __GNUC_PATCHLEVEL__)
…
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200
__GNUG__ : GNU C++ (__GNUC__ && __cplusplus)

#define
#undef
#include
#if #ifdef #ifndef ,
#elif #else else
#endif if