web-dev-qa-db-ja.com

Cで列挙型(enum)を定義するにはどうすればいいですか?

Cの列挙型を使用するための適切な構文が何であるかわかりません。次のようなコードがあります。

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;

しかし、これはコンパイルされず、次のエラーが表示されます。

error: conflicting types for ‘strategy’
error: previous declaration of ‘strategy’ was here

何がおかしいのですか?

259
lindelof

列挙型変数を宣言するには、次のようにします。

enum strategy {RANDOM, IMMEDIATE, SEARCH};
enum strategy my_strategy = IMMEDIATE;

しかし、変数宣言を短くするためにtypedefを使うことができます。

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy my_strategy = IMMEDIATE;

型と変数を区別するための命名規則を持つことは良い考えです。

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy_type;
strategy_type my_strategy = IMMEDIATE;
362
RichieHindle

それはあなたがneedtypedefではないことを指摘する価値があります。次のようにしてください。

enum strategy { RANDOM, IMMEDIATE, SEARCH };
enum strategy my_strategy = IMMEDIATE;

あなたがtypedefを好むかどうかはスタイルの問題です。それがなければ、列挙型を参照したい場合はenum strategyを使用する必要があります。それで、あなたはstrategyと言うことができます。

どちらの方法にも長所と短所があります。 1つは、より言葉遣いですが、通常の識別子と衝突しないように型識別子をtag-namespaceに保持し(struct statstat関数についても考えてください:これらは衝突しません)、すぐに型であることがわかります。もう1つは短いですが、型識別子を通常の名前空間に取り入れます。

446

あなたはstrategyを2回宣言しようとしています、そしてそれはあなたが上記のエラーを得ている理由です。以下は(gcc -ansi -pendantic -Wallでコンパイルされた)苦情なしで動作します。

#include <stdio.h>

enum { RANDOM, IMMEDIATE, SEARCH } strategy = IMMEDIATE;

int main(int argc, char** argv){
    printf("strategy: %d\n", strategy);

    return 0;
}

上記の代わりに、2行目が次のように変更されました。

...
enum { RANDOM, IMMEDIATE, SEARCH } strategy;
strategy = IMMEDIATE;
...

警告から、あなたは簡単にあなたの間違いを見ることができます:

enums.c:5:1: warning: data definition has no type or storage class [enabled by default]
enums.c:5:1: warning: type defaults to ‘int’ in declaration of ‘strategy’ [-Wimplicit-int]
enums.c:5:1: error: conflicting types for ‘strategy’
enums.c:4:36: note: previous declaration of ‘strategy’ was here

そのため、デフォルトの型がstrategyであるintという名前の変数の宣言にコンパイラがstrategy = IMMEDIATEを使用しましたが、この名前の変数の以前の宣言はすでにありました。

ただし、main()関数に代入した場合、それは有効なコードになります。

#include <stdio.h>

enum { RANDOM, IMMEDIATE, SEARCH } strategy = IMMEDIATE;

int main(int argc, char** argv){
    strategy=SEARCH;
    printf("strategy: %d\n", strategy);

    return 0;
}
55
Tarc

あなたが言う時

enum {RANDOM, IMMEDIATE, SEARCH} strategy;

名前のないenumの 'strategy'と呼ばれる単一のインスタンス変数を作成します。これはそれほど便利なことではありません - typedefが必要です。

typedef enum {RANDOM, IMMEDIATE, SEARCH} StrategyType; 
StrategyType strategy = IMMEDIATE;
48
anon

書かれているように、あなたのコードに問題はありません。こんなことをしていないのですか?

int strategy;
...
enum {RANDOM, IMMEDIATE, SEARCH} strategy;

エラーメッセージはどの行を指していますか? 「以前の '戦略'の宣言はここにありました」と言ったとき、何がここにあり、それは何を表していますか?

13
John Bode

投稿された質問へのコメントの@ThoAppelsinは正しいです。コードスニペットは、それが有効で、エラーなしで質問に投稿しました。あなたが持っているエラーはあなたのCソースファイルの他の場所の他の悪い構文によるものでなければなりません。 enum{a,b,c};は、それぞれ01および2の値を持つ整数である3つのシンボリック定数(abおよびc)を定義しますが、enumを使用する場合、通常は特定の整数値を気にしないのでシンボリック定数名これはあなたがこれを持つことができることを意味します:

#include <stdio.h>
enum {a,b,c};
int main(){
  printf("%d\n",b);
  return 0;
}

そしてこれは1を出力します。

これも有効になります。

#include <stdio.h>
enum {a,b,c};
int bb=b;
int main(){
  printf("%d\n",bb);
  return 0;
}

以前と同じように出力されます。

あなたがこれをするならば:

enum {a,b,c};
enum {a,b,c};

あなたはエラーがあるでしょう、しかしあなたがこれをするなら:

enum alfa{a,b,c};
enum alfa;

あなたはエラーがないでしょう。

あなたはこれを行うことができます:

enum {a,b,c};
int aa=a;

そしてaaは値0を持つ整数変数になります。しかし、あなたもこれを行うことができます:

enum {a,b,c} aa= a;

同じ効果があります(つまり、aa0値を持つintです)。

あなたもこれを行うことができます:

enum {a,b,c} aa= a;
aa= 7;

そしてaaは値7を持つintになります。

前述したように、enumを使用して記号定数定義を繰り返すことはできないため、intを使用してenum varsを宣言する場合は、タグを使用する必要があります。

enum tag1 {a,b,c};
enum tag1 var1= a;
enum tag1 var2= b;

typedefを使用すると、毎回enum tag1を記述して変数を定義するのを防ぐことができます。 typedefでは、Tag1と入力するだけです。

typedef enum {a,b,c} Tag1;
Tag1 var1= a;
Tag1 var2= b;

あなたも持つことができます:

typedef enum tag1{a,b,c}Tag1;
Tag1 var1= a;
enum tag1 var2= b;

最後に言うべきことは、定義済みの記号定数について話しているので、enumを使うときは大文字を使うのが良いということです。例えば:

enum {A,B,C};

の代わりに

enum {a,b,c};
11
roggc

C++でtypedefステートメントを必要とせずに "enum"を使用して新しいタイプを定義できることを言及する価値があります。

enum Strategy {RANDOM, IMMEDIATE, SEARCH};
...
Strategy myStrategy = IMMEDIATE;

私はこのアプローチがはるかに友好的であると思います。

[編集 - C++の状態を明確に - 私はもともとこれを持っていたが、それを削除した!]

10
Roddy

宣言について混乱があるようです。

次のようにstrategy{RANDOM, IMMEDIATE, SEARCH}より前になると、

enum strategy {RANDOM, IMMEDIATE, SEARCH};

あなたはenum strategyという名前の新しい型を作成しています。ただし、変数を宣言するときは、enum strategy自体を使用する必要があります。 strategyだけを使用することはできません。したがって、以下は無効です。

enum strategy {RANDOM, IMMEDIATE, SEARCH};
strategy a;

その間、以下は有効です

enum strategy {RANDOM, IMMEDIATE, SEARCH};

enum strategy queen = RANDOM;
enum strategy king = SEARCH;
enum strategy pawn[100];

strategy{RANDOM, IMMEDIATE, SEARCH}の後に来るとき、あなたは匿名のenumを作成して、それからその型の変数であるとstrategyを宣言しています。

だから今、あなたはのような何かをすることができます

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = RANDOM;

ただし、名前を付けたことがないため、enum {RANDOM, IMMEDIATE, SEARCH}型の他の変数を宣言することはできません。だから以下は無効です

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
enum strategy a = RANDOM;

両方の定義を組み合わせることもできます

enum strategy {RANDOM, IMMEDIATE, SEARCH} a, b;

a = RANDOM;
b = SEARCH;
enum strategy c = IMMEDIATE;

前述のようにTypedefは、短い変数宣言を作成するために使用されます。

typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;

enum {RANDOM, IMMEDIATE, SEARCH}strategyと同義語であることをコンパイラに伝えました。それで今あなたは変数型として自由にstrategyを使うことができます。もうenum strategyを入力する必要はありません。以下が有効になりました

strategy x = RANDOM;

Typedefと列挙型の名前を組み合わせて取得することもできます。

typedef enum strategyName {RANDOM, IMMEDIATE, SEARCH} strategy;

strategyenum strategyNameを互換的に使用できるようになったという事実を除けば、このメソッドを使用する利点はそれほどありません。

typedef enum strategyName {RANDOM, IMMEDIATE, SEARCH} strategy;

enum strategyName a = RANDOM;
strategy b = SEARCH;
7
Confuse

列挙の名前を宣言してもエラーは発生しません。

宣言されていない場合は、typedefを使用する必要があります。

enum enum_name {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;

エラーは表示されません。

2
user3135028

私のお気に入りで唯一の中古建築はいつもでした:

typedef enum MyBestEnum
{
    /* good enough */
    GOOD = 0,
    /* even better */
    BETTER,
    /* divine */
    BEST
};

私はこれがあなたが抱えている問題を取り除くと信じています。新しいタイプを使用することは私の観点から正しい選択です。

2
Sany

Tarcの答えは最高です。

列挙型ディスカッションの大部分は、赤いニシンです。

このコードスニペットを比較してください -

int strategy;
strategy = 1;   
void some_function(void) 
{
}

これは

error C2501: 'strategy' : missing storage-class or type specifiers
error C2086: 'strategy' : redefinition

これで問題なくコンパイルできます。

int strategy;
void some_function(void) 
{
    strategy = 1;   
}

変数strategyは、宣言時や関数内などで設定する必要があります。グローバルスコープで、任意のソフトウェア、特に割り当てを書くことはできません。

彼がintの代わりにenum {RANDOM、IMMEDIATE、SEARCH}を使用したという事実は、それを超えて見ることができない人々を混乱させているという意味においてのみ関連性があります。質問の中の再定義エラーメッセージは、これが著者が間違ったことであることを示しています。

それで、今あなたは以下の例の最初が間違っていて、他の3つが大丈夫である理由を見ることができるはずです。

例1間違っている

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
strategy = IMMEDIATE;
void some_function(void) 
{
}

例2正しいです。

enum {RANDOM, IMMEDIATE, SEARCH} strategy = IMMEDIATE;
void some_function(void) 
{
}

例3正しいです。

enum {RANDOM, IMMEDIATE, SEARCH} strategy;
void some_function(void) 
{
    strategy = IMMEDIATE;
}

例4正しいです。

void some_function(void) 
{
    enum {RANDOM, IMMEDIATE, SEARCH} strategy;
    strategy = IMMEDIATE;
}

もしあなたが実用的なプログラムを持っているならば、あなたは単にあなたのプログラムにこれらの断片を貼り付けることができるべきであり、そしてあるものはコンパイルしそしてあるものはそうしないことを見るべきです。

1
user3070485

私はgccを試してみましたが、エラーなしでコンパイルするために、最後の選択肢を使わざるを得なかったので、私の必要性を思いつきました。

typedef enumstate{a = 0、b = 1、c = 2}state;

typedef enum state {a = 0, b = 1, c = 2} state;

typedef enum state old; // New type, alias of the state type.
typedef enum state new; // New type, alias of the state type.

new now     = a;
old before  = b;

printf("State   now = %d \n", now);
printf("Sate before = %d \n\n", before);
0
gg cg