24

たとえば、次のようなマクロは絶対に定義しないでください。

#define DANGER 60 + 2

次のような操作を行うと、これは潜在的に危険な場合があります。

int wrong_value = DANGER * 2; // Expecting 124

代わりに、マクロのユーザーがマクロをどのように使用するかわからないため、次のように定義します。

#define HARMLESS (60 + 2)

例は簡単ですが、それは私の質問をかなり説明しています。マクロを作成するときに推奨する一連のガイドラインまたはベストプラクティスはありますか?

御時間ありがとうございます!

4

11 に答える 11

30

引数を実行して式のように動作するマクロを実行する場合、これは慣用的です。

 #define DOIT(x) do { x } while(0)

このフォームには次の利点があります。

  1. 終了するセミコロンが必要です
  2. ネスティングとブレースで機能します。たとえば、if/elseで機能します。
于 2008-11-26T15:43:26.357 に答える
30

引数を括弧で囲むだけでなく、返される式も括弧で囲む必要があります。

#define MIN(a,b)  a < b ? a : b     // WRONG  

int i = MIN(1,2); // works
int i = MIN(1,1+1); // breaks

#define MIN(a,b)  (a) < (b) ? (a) : (b)   // STILL WRONG

int i = MIN(1,2); // works
int i = MIN(1,1+1); // now works
int i = MIN(1,2) + 1; // breaks

#define MIN(a,b)  ((a) < (b) ? (a) : (b))   // GOOD

int i = MIN(1,2); // works
int i = MIN(1,1+1); // now works
int i = MIN(1,2) + 1; // works

しかし、MIN(3,i++)まだ壊れています...

最良のルールは、他のアプローチが機能しない場合にのみ #defines を使用することです! C++ ではなく C について質問されていることは承知していますが、それでも彼のことを念頭に置いておいてください。

于 2008-11-26T15:49:40.713 に答える
10

マクロ全体、展開リストで参照される各引数を括弧で囲みます。

#define MAX(x, y) ((x) > (y) ? (x) : (y))

引数を複数回評価するマクロを作成することは避けてください。このようなマクロは、引数に副作用がある場合、期待どおりに動作しません。

MAX(a++, b);

より大きいa++場合は 2 回評価されます。ab


マクロには大文字の名前を使用して、それが関数ではなくマクロであることを明確にし、それに応じて違いを考慮できるようにします (もう 1 つの一般的な良い方法は、副作用のある引数を関数に渡さないことです)。


次のようにマクロを使用して型の名前を変更しないでください。

#define pint int *

誰かが入力したときに期待どおりに動作しないため

pint a, b;

代わりに typedef を使用してください。

于 2008-11-26T16:01:35.010 に答える
7

定数値、整数などには、マクロの代わりに静的定数値を使用します。多くの場合、コンパイラーはそれらを最適化することができ、それらは言語の型システムで一流の市民のままです。

static const int DANGER = 60 + 2;
于 2008-11-26T15:43:44.813 に答える
5

展開では、引数を括弧で囲み、式を渡した場合に意図した動作が得られるようにします。

#define LESS_THAN(X,Y) (((X) < (Y) ? (X) : (Y))
于 2008-11-26T15:42:43.160 に答える
5

Linux カーネルの GCC ハックから取得した MAX/MIN マクロへの応答:

#define min(x, y) ({                       \
        typeof(x) _min1 = (x);             \
        typeof(y) _min2 = (y);             \
        (void) (&_min1 == &_min2);         \
        _min1 < _min2 ? _min1 : _min2; })
于 2008-11-26T17:00:36.903 に答える
2

マクロにはグローバル スコープがあり、何かと衝突する可能性があるため、かなり一意の名前を使用してください。

#define MAX 10

他のコードと簡単に衝突する可能性があるため、次のようになります。

#define MYPROJECT_MAX 10

またはさらにユニークなものが良いでしょう。

この種の衝突でコンパイル エラーは発生しないが、わずかに間違ったコードが生成されるケースを見たことがあります。

于 2008-11-26T15:52:41.907 に答える
2

複数行のマクロの場合は、次を使用しますdo { } while (0)

#define foo(x) do {  \
    (x)++;           \
    printf("%d", x); \
} while(0)

やったか

#define foo(x) {     \
    (x)++;           \
    printf("%d", x); \
}

代わりは、

if (xyz)
    foo(y);
else
    foo(z);

失敗したでしょう。

また、マクロに一時変数を導入するときは注意してください。

#define foo(t) do {    \
    int x = (t);       \
    printf("%d\n", x); \
} while(0)

int x = 42;
foo(x);

印刷0されません42

値を返す必要がある複雑な式がある場合は、コンマ演算子を使用できます。

#define allocate(foo, len) (foo->tmp = foo->head, foo->head += len, foo->tmp)
于 2011-05-04T04:14:49.957 に答える
2

マクロを未定義にします。

と一致#definesする必要があり#undefます。これにより、プリプロセッサが詰まって意図しないコードに影響を与えるのを防ぎます。

于 2009-01-16T17:41:21.170 に答える
1

慎重で専門家であれば、マクロを単純なコード ジェネレータとして使用することで、DRY (Don't-Repeat-Yourself) コードを作成できる場合があります。何をしているのかを他のプログラマーに説明する必要はありますが、多くのコードを節約できます。たとえば、リストマクロ手法:

// define a list of variables, error messages, opcodes
// or anything that you have to write multiple things about
#define VARLIST \
    DEFVAR(int, A, 1) \
    DEFVAR(double, B, 2) \
    DEFVAR(int, C, 3) \

// declare the variables
#define DEFVAR(typ, name, val) typ name = (val);
    VARLIST
#undef  DEFVAR

// write a routine to set a variable by name
void SetVar(string varname, double value){
    if (0);
    #define DEFVAR(typ, name, val) else if (varname == #name) name = value;
        VARLIST
    #undef  DEFVAR
    else printf("unrecognized variable %s\n", varname);
}

// write a routine to get a variable's value, given its name
// .. you do it ..

これで、新しい変数を追加したり、削除したり、名前を変更したりしたい場合、それは 1 行の編集です。

于 2008-11-26T16:20:28.980 に答える
0

私がこれをどのように嫌うか見てください:

void bar(void) {
    if(some_cond) {
        #define BAZ ...
        /* some code */
        #undef BAZ
    }
}

常に次のように配置します。

void bar(void) {
    if(some_cond) {
#define BAZ ...
        /* some code */
#undef BAZ
    }
}
于 2008-11-26T17:37:57.327 に答える