ページ 11

Cでのenumの名前衝突

Posted: 2016年5月05日(木) 01:08
by murmur
Cでenumを使っていくつかの状態を管理したいと思っています。

「異常なし」を意味する"NORMAL"というキーワードを基本として、

コード:

typedef enum{
    NORMAL,
    RESETTING,
}state1_t;
typedef enum{
    NORMAL,
    ALLOWED,
}state2_t;
と書きたいのですが、名前の衝突が起こります。
WEB上を見回してみると、structで囲うという手があると書いてあります。その通りに書いてみると、

コード:

typedef struct{
	enum stat{
		NORMAL,
		RESETTING,
	};
}state1_t;
typedef struct{
	enum stat{
		NORMAL,
		ALLOWED,
	};
}state2_t;
これでよいと思ったのですが、どうやら違うようです。

Pleiades MARS (MinGW GCC)使っているのですが、structで囲っても囲わなくても
- redeclaration of enumerator 'NORMAL'
というエラーが出ます。

もしかして、これはC++のみで有効なのでしょうか?
状況の説明が不足でしたらすみません。

Re: Cでのenumの名前衝突

Posted: 2016年5月05日(木) 08:46
by Bull
C言語では列挙子 (enum) 用の名前空間が無いので、たとえ構造体の中に入れても、ダメでしょうね。
マクロを使ってなんとかするという手はあるかもしれませんが、個人的にはやりたくないです。
C++11 以降でしたら、enum struct(class) が使えると思います。

http://qiita.com/ashdik/items/0a11ac75f07c7f80e97a

Re: Cでのenumの名前衝突

Posted: 2016年5月05日(木) 10:10
by murmur
なるほど。名前空間の概念に左右されるということですね。
(C++は少ししか勉強していませんが)
では、C言語でのenumのメンバ(?)は、結局グローバルスコープとしてしか宣言できないので、
便利な#defineの域を出ないといった感じになってしまうのでしょうか。

他に、C言語ではこの、フラグや状態を表す手法としては、
どのようなものがよく用いられているのでしょうか。
いずれにせよ、enumの可読性の良さは捨てがたいですね。

Re: Cでのenumの名前衝突

Posted: 2016年5月05日(木) 12:52
by Bull
名前空間とスコープ(可視範囲)は別の概念です。
#define は単なる文字列の置き換えですので、スコープの概念はありません。
しかし enum にはスコープがありますので、例えば次のようなプログラムはコンパイルが通ります。

コード:

void func1()
{
	typedef enum {
		NORMAL,
		RESETTING,
	}state1_t;
	state1_t	st = NORMAL;
}

void func2()
{
	typedef enum {
		NORMAL,
		ALLOWED,
	}state2_t;

	state2_t	st = NORMAL;
}

int main()
{
	func1();
	func2();
}
でも、使える場面は限られるでしょうね。

この辺を拡張したのが C++11 の enum struct(class) ですかね。

Re: Cでのenumの名前衝突

Posted: 2016年5月07日(土) 20:46
by murmur
ローカルスコープには収まるのですね。

ファイルスコープでは、ファイルスコープ変数のように、
関数外でstaticを付けて実現できるような気もしましたが、
宣言なのでstaticをつけられないのですね。

素直にビットストリームとかを使ったほうが良いのでしょうか。