web-dev-qa-db-ja.com

EnumステートメントとDefineステートメントの違い

C/C++での定義ステートメントと列挙ステートメントの使用の違いは何ですか(CまたはC++でそれらを使用する場合に違いはありますか)?

たとえば、いつ使用すべきか

enum {BUFFER = 1234}; 

以上

#define BUFFER 1234   
45
Zain Rizvi

enumは構文要素を定義します。

#defineはプリプロセッサディレクティブで、実行されますbeforeコンパイラはコードを認識するため、C自体の言語要素ではありません。

一般的に列挙型は、タイプセーフであり、より簡単に検出できるため、推奨されます。定義は見つけるのが難しく、複雑な動作をする可能性があります。たとえば、あるコードが別のコードによって作成された#defineを再定義できます。これを追跡するのは難しい場合があります。

57
Jason Cohen

#defineステートメントは、コンパイラーがコードを見る前にプリプロセッサーによって処理されるため、基本的にはテキスト置換です(実際にはパラメーターなどを使用すると、少しインテリジェントになります)。

列挙型はC言語自体の一部であり、次の利点があります。

1 /それらはタイプを持っているかもしれません、そして、コンパイラはそれらをタイプチェックすることができます。

2 /コンパイラーで使用できるため、それらのシンボル情報をデバッガーに渡すことができ、デバッグが容易になります。

17
paxdiablo

Defineはプリプロセッサコマンドです。エディターで「replace all」を実行するのと同じで、文字列を別の文字列に置き換えて結果をコンパイルできます。

Enumはタイプの特殊なケースです。たとえば、次のように記述した場合、

enum ERROR_TYPES
{
   REGULAR_ERR =1,
   OK =0
}

eRROR_TYPESという新しいタイプが存在します。 REGULAR_ERRが1になることは事実ですが、この型からintにキャストすると、キャストの警告が生成されます(コンパイラーを高冗長に構成している場合)。

概要:どちらも似ていますが、列挙型を使用する場合、型チェックを利用し、定義を使用することで、コード文字列を置き換えるだけです。

8
akiva

列挙型を使用することが理にかなっている場合、列挙型は一般的に#defineよりも優先されます。

  • デバッガーは、enums値のシンボリック名を表示できます( "openType: OpenExisting"ではなく、 "openType: 2")
  • 名前の衝突からもう少し保護されますが、これはそれほど問題ではありません(ほとんどのコンパイラはre#defineitionについて警告します。

最大の違いは、列挙型を型として使用できることです。

// Yeah, dumb example
enum OpenType {
    OpenExisting,
    OpenOrCreate,
    Truncate
};

void OpenFile(const char* filename, OpenType openType, int bufferSize);

これにより、パラメーターの型チェックが可能になり(openTypeとbufferSizeを簡単に混同することはできません)、有効な値を簡単に見つけることができるため、インターフェースがはるかに使いやすくなります。一部のIDEでは、 インテリセンス コード完成!

5
Simon Buchan

可能な場合は常に列挙型を使用することをお勧めします。列挙型を使用すると、コンパイラにソースコードに関する詳細情報が提供されます。プリプロセッサ定義はコンパイラーから見られないため、情報が少なくなります。

実装用列挙型を使用する一連のモードにより、たとえば、コンパイラーがスイッチで欠落しているcase- statementsをキャッチできるようになります。

4
unwind

enumは、1つのカテゴリに複数の要素をグループ化できます。

enum fruits{ Apple=1234, orange=12345};

一方、#defineは無関係な定数のみを作成できます。

#define Apple 1234
#define orange 12345
3
Andy

#defineはプリプロセッサコマンド、enumはCまたはC++言語です

この種のケースでは、#defineよりも列挙型を使用する方が常に適切です。 1つはタイプセーフです。もう1つは、値のシーケンスがある場合、列挙のシーケンスの開始を指定するだけでよく、他の値は連続した値を取得することです。

enum {
  ONE = 1,
  TWO,
  THREE,
  FOUR
};

の代わりに

#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4

補足として、#define(定数を含む識別子を作成する必要がある場合は通常、ある種のマクロに対して)を使用する必要がある場合もありますが、それは一種のマクロの黒魔術です、そして行く方法であることは非常にまれです。これらの端部に行く場合は、おそらくC++テンプレートを使用する必要があります(ただし、Cにこだわっている場合は...)。

3
kriss

すでに書かれたすべてのものに加えて、1人は言ったが示されていない代わりに興味深い。例えば。

enum action { DO_JUMP, DO_TURNL, DO_TURNR, DO_STOP };
//...
void do_action( enum action anAction, info_t x );

タイプとしてアクションを考慮すると、事がより明確になります。定義を使用して、あなたは書いたでしょう

void do_action(int anAction, info_t x);
2
ShinTakezou

整数定数値については、#defineよりもenumを優先するようになりました。 enumを使用しても不都合はないようです(少しタイピングを行うことによる非常に小さな不利な点は無視します)が、enumにスコープを設定できるという利点がありますが、#define識別子にはすべてを網羅するグローバルスコープがあります。

通常、#defineを使用することは問題ありませんが、enumには欠点がないため、これを使用します。

C++では、enumはCに移植可能であるため(Cとは異なり)、C++ではconst intをリテラル整数値の代わりに使用できますが、enumconst intよりも一般的に優先されます(まだ多くの作業を行っています)。

2
Michael Burr

この単一の定数(たとえば、buffersize)だけが必要な場合は、列挙型ではなく定義を使用します。列挙型は、戻り値(さまざまなエラー条件を意味します)などのさまざまな「タイプ」または「ケース」を区別する必要がある場合に使用します。その場合、列挙型を使用して、関数のプロトタイプなどで使用できる新しい型を作成できます。その後、コンパイラーはそのコードをより適切に検証できます。

2
Henno Brandsma

定義のリストに対する列挙型のもう1つの利点は、switchステートメントですべての値がチェックされない場合に、コンパイラー(少なくともgcc)が警告を生成できることです。例えば:

enum {
    STATE_ONE,
    STATE_TWO,
    STATE_THREE
};

...

switch (state) {
case STATE_ONE:
    handle_state_one();
    break;
case STATE_TWO:
    handle_state_two();
    break;
};

前のコードでは、コンパイラは列挙型のすべての値がスイッチで処理されるわけではないという警告を生成できます。州が#defineとして行われた場合、これは当てはまりません。

1
Russell Bryant

定数のグループ(「曜日」など)がある場合、列挙型がグループ化されていることを示しているため、列挙型の方が適しています。そして、ジェイソンが言ったように、それらはタイプセーフです。それがグローバル定数(バージョン番号など)である場合は、#defineを使用することになります。これは多くの議論の主題ですが。

1
Smashery

上記のいくつかの答えは、さまざまな理由で列挙型を使用することをお勧めしますが、インターフェイスを開発するときは、定義を使用することが実際の利点であることを指摘しておきます。新しいオプションを導入して、ソフトウェアに条件付きで使用させることができます。

例えば:

 
 #define OPT_X1 1/*バージョン1で導入*/
 #define OPT_X2 2/*バージョン2で導入*/
 

次に、どちらかのバージョンでコンパイルできるソフトウェア

 
 #ifdef OPT_X2 
 int flags = OPT_X2; 
 #else 
 int flags = 0; 
 #endif 
 

列挙型では、これはランタイム機能検出メカニズムなしでは不可能です。

1
Nikos

列挙型を作成すると、リテラルだけでなく、これらのリテラルをグループ化するタイプも作成されます。これにより、コンパイラーがチェックできる意味がコードに追加されます。

さらに、デバッガーを使用する場合は、列挙リテラルの値にアクセスできます。これは常に#defineの場合とは限りません。

1
mouviciel

上記の優れた点に加えて、列挙型のスコープをクラス、構造体、または名前空間に制限できます。個人的に、私はいつでもスコープ内に関連するシンボルの最小数を保持するのが好きです。これは、#definesではなく列挙型を使用するもう1つの理由です。

1
SmacL

列挙型:

1。通常、複数の値に使用されます

2。enumには、名前と名前の値の2つがあります。名前の値は区別する必要がありますが、値は同じでもかまいません。値を定義しない場合、明示的に値が指定されていない限り、列挙名の最初の値は0、2番目の値は1、というようになります。

3。タイプがある可能性があり、コンパイラはタイプチェックできます

4。デバッグを簡単にする

5。スコープをクラスに制限できます。

定義:

1。値を1つだけ定義する必要がある場合

2。通常、ある文字列を別の文字列に置き換えます。

3。スコープはグローバルであり、スコープを制限できません

全体として、列挙型を使用する必要があります

1
user8194964

列挙型は、週の日数など、ある種のセットを列挙するために使用されます。定数が1つだけ必要な場合は、const int(またはdoubleなど)は、列挙型よりも明らかに優れています。個人的には嫌いです#define(少なくとも一部の定数の定義ではありません)。これは、タイプセーフではないためです。ただし、それが適切であれば、もちろん使用できます。

1
PeterK

違いはほとんどありません。 C規格では、列挙には整数型があり、列挙定数はint型であるため、エラーなしで両方を他の整数型と自由に混在させることができます。 (その一方で、明示的なキャストなしにそのような混合が許可されない場合、列挙型の賢明な使用が特定のプログラミングエラーをキャッチする可能性があります。)

列挙型のいくつかの利点は、数値が自動的に割り当てられること、列挙型変数が検査されるときにデバッガーがシンボリック値を表示できること、およびそれらがブロックスコープに従うことです。 (列挙が無差別に混合されている場合、厳密に違法ではありませんが、悪いスタイルと見なされる可能性があるため、コンパイラーは致命的でない警告を生成することもあります。)欠点は、プログラマーが致命的でない警告をほとんど制御できないことです。一部のプログラマーは、列挙型変数のサイズを制御できないことに憤慨しています。

0
x0v