enum値の逆引きをする関数を生成する
以前、同期からされた質問で、
enum enum_type{ hoge,fuga,aho };
という宣言に対して、
enum enum_type v = fuga; printf("%s",search(v)); //=> fuga
という感じで、enumに定義した識別子を文字列として出力するようなsearch関数を自動的に作れないか?というもの。
そのときはそんなんできねーよってことで終わってしまったんだけど、エラー出力のときとかに役に立つしなんとかなんないかなーと自分なりに考えてみた。
最初のマクロ
#define ENUMERATION(type, e0,e1,e2,e3) enum type { e0,e1,e2,e3 }; \ const char type[][16] = { #e0,#e1,#e2,#e3 }; ENUMERATION(test, hoge, fuga, aho, baka); ... printf("%s",test[fuga]); //=> fuga
配列の中に文字列化した識別子を入れてみる。enumの途中でaho=100とかはこの際考えてない。多少メモリ喰うけど、検索の必要もないしいいんじゃないかと。
ただ、マクロが可変引数を扱えないのでenumに要素を追加しようと思ったら、4箇所も書き換えなくてはいけない。ENUMERATIONの引数に追加するだけで何とかならんのか…?
調べてみると、C99では__VA_ARGS__によってマクロで可変引数が扱えるようになったらしい。C89が望ましいんだけど、試しに使ってみる。
#define ENUMERATION(type, ...) enum type { __VA_ARGS__ };
…って、__VA_ARGS__から引数それぞれに対して文字列化するやり方がわからんつーか存在しないのか??
しょうがないので、#__VA_SRGS__という文字列を保存しておいて、問い合わせがあるたびに文字列をサーチする関数を作った。
最終的なコードは以下
#define ENUMERATION_INIT() char _enum_ret[16]; #define ENUMERATION(type, ...) enum type { __VA_ARGS__ };\ char *type = #__VA_ARGS__;\ char *search_##type(enum type e) {\ _enum_search(type,_enum_ret,e);\ return _enum_ret;\ } static void _enum_search(char *enum_type, char *tmp, int n) { int len=0,cnt=0; char *st,*end; for(st = enum_type ; st != '\0' && cnt < n ; st++) if(*st == ',') cnt++; if(st == '\0') { *tmp = '\0'; return; } while(st ==" ") st++; for(end = st ; end != '\0' && *end != ',' && *end != ' '; len++, end++) ; strncpy(tmp,st,len); tmp[len] = '\0'; }
えらい長くなった……
使ってみる。
ENUMERATION_INIT(); ENUMERATION(word, hoge,fuga,aho,baka); ENUMERATION(word2, poi,hoi,hei,doi); .... enum word a = fuga; printf("%s\n",search_word(a)); //=>fuga printf("%s\n",search_word2(0)); //=>poi printf("%s\n",search_word(aho)); //=>aho
最初のマクロと比べると検索に時間かかるなあ。それにINITとかめんどうで嫌だなあ……enum typeごとに検索結果格納用のバッファ作ってもいいけど、メモリが無駄。
だいたい可変引数を解釈してくれれば最初の2行のマクロでよかったのに。