私は技術面接でこの質問をされました:
const
とC++のマクロの違いは何ですか?
私の答えは、マクロはプリプロセッサディレクティブであり、コンパイル前に定数式に置き換えられるため、マクロを使用するとアプリケーションのデバッグが困難になる可能性があるのに対し、const
は型識別子を持つことができ、デバッグが簡単です。
誰かが他の違いを指摘できますか?どちらが好ましいですか?
編集:
C++のIBM資料から:
#define
とconst
型修飾子の違いは次のとおりです。
#define
ディレクティブを使用して、数値、文字、または文字列定数の名前を作成できますが、任意のタイプのconstオブジェクトを宣言できます。Constオブジェクトは変数のスコープ規則に従いますが、
#define
を使用して作成された定数はそうではありません。const
オブジェクトとは異なり、マクロの値はインライン展開されるため、コンパイラーが使用する中間ソースコードには表示されません。インライン展開により、デバッガーはマクロ値を使用できなくなります。マクロは、配列バインドなどの定数式で使用できますが、
const
オブジェクトは使用できません。 (array_size
を定義するにはマクロを使用する必要があると思います。コンパイラは、マクロ引数を含むマクロの型チェックを行いません。
マクロと定数はリモートで同じものではなく、それぞれが状況に適している場合があり、あなたの答えは違いの表面をかすっただけです。また、C++には2種類の定数があります。
const
修飾子で定義された定数は、変更不可能変数として最もよく考えられます。変数のすべてのプロパティがあります。タイプ、サイズ、リンケージがあり、アドレスを取得できます。 (コンパイラーは、これらのプロパティの一部を最適化して回避できる場合があります。たとえば、アドレスが使用されない定数は実行可能イメージに出力されない場合があります。ただし、これはas-ifルールのおかげです。 )const
データムに対して実行できない唯一のことは、その値を変更することです。 enum
で定義された定数は少し異なります。タイプとサイズはありますが、リンケージがなく、アドレスを取得できず、タイプは一意です。これらは両方とも変換フェーズ7で処理されるため、左辺値または右辺値以外の何物でもありません。 (前の文の専門用語については申し訳ありませんが、それ以外の場合はいくつかの段落を書く必要があります。)
マクロの制約ははるかに少なく、プログラム全体が整形式のプログラムである限り、トークンの任意のシーケンスに拡張できます。変数のプロパティはありません。 sizeof
または&
をマクロに適用すると、マクロの展開先に応じて、何か便利なことができる場合とできない場合があります。マクロは、数値リテラルに展開するように定義される場合があり、そのようなマクロは定数として考えられる場合がありますが、「コンパイラー固有」(つまり、変換フェーズ7)は、それらを数値リテラルと見なします。
今日では、定数を使用するときにマクロを使用しないことは、一般的に良い習慣と考えられています。マクロは他のすべての識別子と同じスコープ規則に従わないため、混乱する可能性があります。定数を使用すると、変換フェーズ7に、したがってデバッガーにも詳細情報が提供されます。ただし、マクロを使用すると、他の方法では実行できないことを実行できます。これらのいずれかを実行する必要がある場合は、遠慮なく使用してください。 (この意味で、重みを引いているマクロは、一般的にnotを数値リテラルに展開しますが、決して言うつもりはありません。)
EDIT:これは何か面白いことをするマクロの例です。それは決して定数を形作ったり形作ったりするものではありません。マクロなしで同じ効果を得る方法があるかもしれませんが(文字列ストリームを含まないものを知っているなら、それについて聞いてみたいです!)、それは力と両方の良い例証になると思いますマクロの危険性(後者の場合、1つの非常に特定のコンテキストの外で使用された場合にどうなるかを検討してください...)
static double elapsed()
{ ... }
#define ELAPSED '[' << std::fixed << std::setprecision(2) << elapsed() << "] "
// usage:
for (vector<string>::iterator f = files.begin(); f != files.end(); f++) {
cout << ELAPSED << "reading file: " << *f << '\n';
process_file(*f);
}
いくつかの理由から、const int sum = 1;
よりも#define sum 1
を優先する必要があります。
スコープベースのメカニズム:
#define
sはスコープを尊重しないため、クラススコープの名前空間を作成する方法はありません。 const変数は、クラス内でスコープを設定できます。
コンパイルエラー中の奇妙なマジックナンバーの回避:
#define
を使用している場合、プリコンパイル時にプリプロセッサに置き換えられます。したがって、コンパイル中にエラーが発生した場合、エラーメッセージはマクロ名ではなく値を参照し、表示されるため、混乱を招きます。突然の値であり、コードでそれを追跡するのに多くの時間を浪費するでしょう。
デバッグのしやすさ:
また、同じ理由で、#define
をデバッグしても、実際には役に立ちません。
上記の両方の状況を回避するには、const
の方が適しています。
もう1つの違いは、const
変数にはメモリがあり、ポインタで参照できることです。マクロはコンパイル前に発生するオートコンプリートであるため、コンパイル中に名前が失われます。
また、マクロは定数以上のものにすることができます。関数の定義全体であっても、式または構文的に正しいものであれば何でもかまいません。
マクロは、プログラミングの選択を表すために使用されます。スタックサイズ;一方、cosnt
は、Piやeの値などの実世界の定数を表すために使用されます。
(元々投稿された static const vs #define -この質問はより「勢い」があるように思われるのでここで再現...それが不適切かどうか教えてください...)
使用法に応じて、すべての長所と短所:
#define
_ ala #define S std::string("abc")
を「入力」しようとするかもしれませんが、定数は、使用の各ポイントで別個の一時的なものを繰り返し構築することを回避します。#define X "x"
_とクライアントの使用法が_"pre" X "post"
_の場合、Xを定数ではなく実行時に変更可能な変数にする必要がある場合に問題が発生することですが、その移行は_const char*
_または_const std::string
_は、既にユーザーに連結操作を組み込むように強制している場合。{ 1, 2 }
_などの「定数」または_#define MICROSECONDS *1E-6
_などを作成します。(間違いなくこれはお勧めしません!)__FILE__
_や___LINE__
_のようないくつかの特別なものをマクロ置換に組み込むことができますtemplate <typename T> void f(T t) { cout << ++t; }
はコンパイルされません)template <typename T> void f(T)
は、異なる列挙型から同じ数値が渡されると、異なるインスタンス化を取得します。これらはすべて、実際のf(int)インスタンス化とは異なります。 。原則として、私はconstsを使用し、それらを一般的な使用法の最も専門的なオプションと見なします(ただし、他のconstsは、この古い怠惰なプログラマーにとって魅力的な単純さを持っています)。
マクロはスコープを尊重せず、マクロの名前はシンボリックデバッガーで使用できない場合があります。 Dan Saks には、マクロ(なし)、定数オブジェクト、および列挙定数の相対的なメリットに関するかなり完全な記事があります。 Stephen Dewhurst のように、Saksは、ストレージを使用しないため、整数値の列挙定数を優先します(より正確には、列挙定数にはストレージ期間もリンケージもありません)。
サンプル:ソース:main.cpp
#define int_constance 4
#define int_constance 8 // ok, compiler will warning ( redefine macro)
const int a = 2;
const int a = 4; // redefine -> error
int main(int argc, char** argv)
{
std::cout << int_constance ; // if remove second #define line, output will be 8
return 0;
}