5

Cでtypedef列挙型の追加データを定義するための最良のアプローチは何ですか?

例:

typedef enum {
  kVizsla = 0,
  kTerrier = 3,
  kYellowLab = 10
} DogType;

ここで、それぞれの名前を定義したいと思います。たとえば、kVizsla「vizsla」のようにします。私は現在、大きなスイッチブロックを使用して文字列を返す関数を使用しています。

4

4 に答える 4

3

X() マクロに最適です。これらのタイプのマクロは、C プリプロセッサを使用して、同じソースから列挙型と配列を構築できます。X() マクロを含む #define に新しいデータを追加するだけです。

あなたの例は次のように書くことができます:

// All dog data goes in this list
#define XDOGTYPE \
  X(kVizsla,0,"vizsla") \
  X(kTerrier,3,"terrier") \
  X(kYellowLab,10,"yellowlab")

 // Dog info
 typedef struct {
     int val;       // Defined value
     char * desc;   // Text description
 } DogType;

 // Build an array index using the Names
 typedef enum {
  #define X(Name,Val,Text)     Name,
   XDOGTYPE
  #undef X
  MAXDOGS
 } DogIndex;

 // Build a lookup table of values
 DogType Dog[] = {
  #define X(Name,Val,Text)    {Val,Text},
   XDOGTYPE
  #undef X
 };

 // Access the values
 for (i=0; i < MAXDOGS; i++)
    printf("%d: %s\n",Dog[i].val,Dog[i].desc);
于 2008-09-02T15:34:18.477 に答える
2

@dmckee: 提案された解決策は良いと思いますが、単純なデータ (名前だけが必要な場合など) の場合は、自動生成されたコードで拡張できます。コードを自動生成する方法はたくさんありますが、このような単純なものについては、列挙型の XML 表現を取り込んでコード ファイルを出力する単純な XSLT を記述できると思います。

XML は次の形式になります。

<EnumsDefinition>
    <Enum name="DogType">
        <Value name="Vizsla" value="0" />
        <Value name="Terrier" value="3" />
        <Value name="YellowLab" value="10" />
    </Enum>
</EnumsDefinition>

結果のコードは、dmckee が彼のソリューションで提案したものに似たものになります。

このような XSLT の書き方については、こちらを試すか、Google で検索して適切なチュートリアルを見つけてください。XSLT を書くのはあまり楽しい IMO ではありませんが、少なくともこれらのような比較的単純なタスクの場合はそれほど悪くはありません。

于 2008-08-30T16:12:23.120 に答える
1

列挙値が十分に密集している場合は、文字列を保持する配列を定義し、それらを検索することができます(スキップされた値にはNULLを使用し、検索ルーチンに特殊なケースハンドラーを追加します)。

char *DogList[] = {
  "vizsla", /* element 0 */
  NULL,
  NULL,
  NULL,
  "terrier", /* element 3 */
  ...
};

これは、スパース列挙には非効率的です。

列挙が密ではない場合でも、構造体の配列を使用してマッピングを保持できます。

typedef struct DogMaps {
  DogType index;
  char * name;
} DogMapt;
DogMapt DogMap[] = {
  {kVizsla, "vizsla"},
  {kTerrier, "terrier"},
  {kYellowLab, "yellow lab"},
  NULL
};

2番目のアプローチは非常に柔軟性がありますが、データを使用する必要があるたびにマッピングを検索することを意味します。大規模なデータセットの場合は、配列ではなくbツリーまたはハッシュを検討してください。

どちらの方法も一般化して、より多くのデータを接続できます。最初の使用では構造体の配列を使用し、2番目の使用では構造体にメンバーを追加するだけです。

もちろん、これらのデータ構造との相互作用を単純化するために、さまざまなハンドラーを作成する必要があります。


@Hershiどうしても、コードとデータを分けてください。上記の例は、機能的ではなく明確にすることを目的としています。

私は、あなたが示すような構造化された入力ではなく、その目的のために空白で区切られたフラットファイルをまだ使用していることを認めますが、私のプロダクションコードは、外部ソースから可能な限り多くのデータを読み取ります。


待ってください、あなたはコード生成を意味しているようです。

もちろん。それは何も悪いことではありません。

OPは、生成されたコードがどのように見えるかに関心を持っていたのではないかと思います...

于 2008-08-30T14:45:29.880 に答える
0

これは自由回答形式の質問ですが、キー タイプとして列挙型を使用し、値に追加情報を含むマップを使用することをお勧めします。(例とは異なり、インデックスが連続している場合は、マップの代わりにシーケンス コンテナーを使用できます)。

于 2008-08-30T14:38:57.730 に答える