web-dev-qa-db-ja.com

C ++-列挙型vs.定数vs.#define

ここの記事の終わりに: http://www.learncpp.com/cpp-tutorial/45-enumerated-types/ 、それは次のように述べています:

最後に、定数変数と同様に、列挙型がデバッガーに表示され、この点で#defined値よりも便利になります

上記の太字の文はどのように達成されますか?

ありがとう。

29
Simplicity

このコードを検討してください、

#define WIDTH 300

enum econst
{
   eWidth=300
};

const int Width=300;

struct sample{};

int main() 
{
        sample s;
        int x = eWidth * s; //error 1
        int y = WIDTH * s;  //error 2
        int z = Width * s;  //error 3
        return 0;
}

明らかに、各乗算はコンパイルエラーになりますが、GCCが各乗算エラーのメッセージをどのように生成するかを確認してください:

prog.cpp:19:エラー:「eWidth * s」の「operator *」に一致しません
prog.cpp:20:エラー:「300 * s」の「operator *」に一致しません
prog.cpp:21:エラー:「Width * s」の「operator *」に一致しません

エラーメッセージに、#definedのマクロWIDTHが表示されていませんね。これは、GCCが行をコンパイルしようとすると、2番目のエラーに対応するため、WIDTHは表示されず、GCCが行をコンパイルする前のように、300のみが表示されるため、プリプロセッサにはalreadyWIDTHを300に置き換えました。一方、enumではそのようなことは起こりません。 )eWidthおよびconstWidth

ここで自分でエラーを確認してください: http://www.ideone.com/naZ3P


また、ScottMeyersによるEffective C++からItem 2 : Prefer consts, enums, and inlines to #definesを読んでください。

30
Nawaz

enumは、ストレージ割り当てのないデバッグ情報を含むコンパイル時定数です。

constは、定数伝搬を使用してコンパイラーによって最適化されているかどうかに応じて、ストレージに割り当てられます。

#defineストレージの割り当てはありません。

14
Sun Shine

#define値は、宣言された値を持つプリプロセッサによって置き換えられるため、デバッガーでは、値のみが表示され、#defined名は表示されません。 #define NUMBER_OF_CATS 10がある場合、デバッガーには10しか表示されません(プリプロセッサーがコード内のNUMBER_OF_CATSのすべてのインスタンスを10に置き換えたためです。

列挙型はそれ自体が型であり、値はこの型の定数インスタンスであるため、プリプロセッサはそれをそのままにして、デバッガーに値の記号的な説明が表示されます。

6
Jackson Pope

プログラムが特定のオプションを使用してコンパイルされると、コンパイラは列挙型情報をバイナリに格納します。

変数が列挙型の場合、デバッガーは列挙名を表示できます。これは、例で最もよく示されています。

enum E {
    ONE_E = 1,
};

int main(void)
{
    enum E e = 1;

    return 0;
}

これをgcc -gでコンパイルすると、gdbで次のことを試すことができます。

Reading symbols from test...done.
(gdb) b main
Breakpoint 1 at 0x804839a: file test.c, line 8.
(gdb) run
Starting program: test 

Breakpoint 1, main () at test.c:7
7               enum E e = 1;
(gdb) next
9               return 0;
(gdb) print e
$1 = ONE_E
(gdb) 

定義を使用した場合、eを指定するための適切な型がなく、整数を使用する必要があります。その場合、コンパイラは1の代わりにONE_Eを出力します。

-gフラグは、gdbにデバッグ情報をバイナリに追加するように要求します。次を発行することで、そこにあることを確認することもできます。

xxd test | grep ONE_E

ただし、これがすべてのアーキテクチャで機能するとは思いません。

3
Penz

少なくとも私が現在手元にあるVisualStudio 2008については、この文は正しいです。あなたが持っている場合

#define X 3
enum MyEnum
{
    MyX = 3
};

int main(int argc, char* argv[])
{
    int i = X;
    int j = (int)MyX;
    return 0;
}

mainにブレークポントを設定すると、マウスを「MyX」に合わせると、評価が3になることがわかります。Xにカーソルを合わせると、何も役に立ちません。

ただし、これは言語プロパティではなく、IDEの動作です。次のバージョンでは、他のIDEと同様に、動作が異なる可能性があります。IDE =この文があなたのケースに当てはまるかどうかを確認します。

1
Philipp

次の記事を確認してください、ニースの要約 http://www.queryhome.com/26340/define-vs-enum-vs-constant

0
user19866

答えが遅すぎますが、何かを追加できると思います-列挙型vs.定数vs. #define

列挙型-

  1. 値を割り当てる必要はありません(連続した値0、1、2 ..が必要な場合)が、#definesの場合は、手動で値を管理する必要があり、ヒューマンエラーが発生する可能性があります。
  2. これは、オンラインデバッグ中に変数として機能し、列挙型の値をウォッチウィンドウで監視できます。
  3. 列挙型を割り当てることができる列挙型の変数を持つことができます

    typedef列挙型番号{DFAULT、CASE_TRUE、CASE_OTHER、};

    int main(void){数値number = CASE_TRUE; }

const-

  1. これはメモリの読み取り専用領域に常に格納されますが、#define の場合は不可能なアドレスを使用してアクセスできます。
    1. #defineではなくconstを使用する場合は、タイプチェックを手に入れます
  2. 定義は前処理ディレクティブですが、constはたとえばコンパイル時です

    const char * name = "vikas";

名前にアクセスし、そのベースアドレスを使用して、vikas [3]などを読み取って「a」などを読み取ることができます。

#defines-テキスト置換を行うダムプリプロセッサディレクティブです

0
Vicky