本当の問題は、定義が言語の残りの部分 (プリプロセッサ) とは異なるツールによって処理されることです。結果として、コンパイラはそれを認識せず、プリプロセッサ名の再利用など、何か問題が発生した場合にユーザーを助けることができません。
max
マクロとして実装されることがあるケースを考えてみましょう。結果として、max
コード内のどこでも識別子を使用することはできません。どこでも。しかし、コンパイラは教えてくれません。代わりに、コードがひどく間違ってしまい、その理由がわかりません。
さて、この問題は、注意を払って最小限に抑えることができます (完全に排除されていない場合)。しかし、ほとんどの用途で#define
は、より良い代替手段があるため、費用対効果の計算が歪められます。メリットがまったくないのにわずかなデメリットがあります。利点がないのに、なぜ欠陥のある機能を使用するのでしょうか?
したがって、ここに非常に単純な図があります。
- 定数が必要ですか?定数を使用する (定義ではない)
- 関数が必要ですか?関数を使用する (定義ではない)
- 定数や関数を使用してモデル化できないものが必要ですか? 定義を使用しますが、適切に行ってください。
それを「適切に」行うこと自体が芸術ですが、簡単なガイドラインがいくつかあります。
固有の名前を使用してください。すべて大文字で、常に一意のライブラリ識別子が前に付きます。max
? 外。VERSION
? 外。代わりに、 と を使用MY_COOL_LIBRARY_MAX
しMY_COOL_LIBRARY_VERSION
ます。たとえば、Boost ライブラリ、マクロの大量のユーザーは、常に で始まるマクロを使用しますBOOST_<LIBRARY_NAME>_
。
評価に注意。実際には、マクロ内のパラメーターは置き換えられる単なるテキストです。結果として、#define MY_LIB_MULTIPLY(x) x * x
は壊れています: として使用できMY_LIB_MULTIPLY(2 + 5)
、結果として2 + 5 * 2 + 5
. 私たちが望んでいたものではありません。これを防ぐために、常に引数のすべての使用を括弧で囲みます (自分が何をしているのか正確にわかっている場合を除きます – ネタバレ: おそらく知らないでしょう。専門家でさえ驚くほど頻繁にこれを間違えます)。
このマクロの正しいバージョンは次のようになります。
#define MY_LIB_MULTIPLY(x) ((x) * (x))
しかし、マクロをひどく間違ったものにする方法はまだたくさんあります。繰り返しますが、コンパイラはここでは役に立ちません。