3

私が求めているのがばかげたものなのかどうかさえわかりません。コードを書いてくださいと言っているわけではありませんが、何かをより良い方法で行うためのアイデアです。

次のような多数のアイテムを持つ構造体があります。

typedef struct _myStruct
{
    int int1;
    char char1;
    int int2;
    :
    :
    int int50;
}myStruct;

myStruct の各項目に対して 1 つのエントリを持つ別の列挙があります。

enum
{
   eINT1,
   eCHAR1,
   eINT2,
   :
   :
   eINT50
} PARAMETER_ID;

が入力として与えられmyStructたときに、のメンバーの値を返す各データ型 [int 用、char 用、string 用など] ごとに関数を作成したいと考えています。PARAMETER_ID

たとえば、引数として eINT1 が渡されたときint GetInt(PARAMETER_ID)の値を返す関数が必要です。int1同様にchar GetCharacter(PARAMETER_ID)float GetFloat(PARAMETER_ID)などがあります。

構造体の項目数が多くなる場合があります。そのため、各アイテムにスイッチ ケースを使用することは、実行可能なオプションではありません。

私が考えることができる他の唯一のオプションは、構造変数とoffsetof()関数のアドレスを使用してパラメーターのアドレスを計算しmemcpy、必要なバイトを変数に入れることです。その場合、各パラメーターのオフセットをどこかに保持する必要がありますが、それは問題ではありません。

これを行うための代替オプションを探しています。どんな助けでも大歓迎です。

ありがとうございました。

4

3 に答える 3

5

大型switchは実行可能な優れたオプションです。

プリプロセッサのトリックをプレイすることもできます。

mystruct.defを含むファイルを持つことができます

 INTFIELD(int1)
 CHARFIELD(char1)
 INTFIELD(int2)

など...次に、それを数回含めます。構造を宣言するには:

 struct _myStruct {
 #define INTFIELD(F) int F;
 #define CHARFIELD(F) char F;
 #include "mystruct.def"
 #undef INTFIELD
 #undef CHARFIELD
 };

列挙を宣言するには (e_int1の代わりに使用eINT1)

 enum field_en {
 #define INTFIELD(F) e_##F,
 #define CHARFIELD(F) e_##F,
 #include "mystruct.def"
 #undef INTFIELD
 #undef CHARFIELD
 };

アクセサーを実装するには、

 int get_int(struct _myStruct*s, enum field_en f)
 {
    switch (f) {
 #define INTFIELD(F) case e_##F: return s->F;
 #define CHARFIELD(F) /*nothing*/
 #include "mystruct.def"
 #undef INTFIELD
 #undef CHARFIELD
    default: return 0;
 }}

これがより優れた、またはより読みやすいコードであるとは主張しませんが、その種のプログラミング スタイルは一部の C または C++ プログラムに見られます (たとえば、GCC 内部とそのgcc/tree.def)

コードが非常に大規模なコード ベースであり、何日も作業する準備ができている場合 (たとえば、そのようなものがたくさんあり、そのstructようなトリックを実行したくない場合)、MELTを使用して GCC 拡張機能を作成することを検討できます(高い-GCC を拡張するレベルのドメイン固有言語) を支援します。MELT 拡張機能を作成して、アクセサ関数を生成することができます。

また、アドホックな記述ファイルから 、 、およびアクセサ関数のstruct両方を生成するように上司を説得することもできます ( などを使用)。GCC は、そのオプション ファイルに対してそのようなトリックを行います。enumawkpythongcc/common.opt

最後に、 を含むヘッダー_myStructが非常に神聖で触ることができない場合、および非常にきれいにフォーマットされている場合は、アドホック (例: awk) スクリプトを作成してその宣言を取得し、処理することができます。

NB 優れたコンパイラswitchは、数百の場合でも、一定の時間がかかるインデックス付きジャンプとして高密度ステートメントを最適化します。

于 2013-02-18T07:25:14.557 に答える
3
#include <stddef.h>
#include <stdio.h>

struct S
{
 int  int1;
 char char1;
 int  int2;
 char char2;
 long long1;
} myStruct = {12345, 'A', 321, 'B', -1L};

enum
{
 eINT1  = offsetof(struct S, int1),
 eCHAR1 = offsetof(struct S, char1),
 eINT2  = offsetof(struct S, int2),
 eCHAR2 = offsetof(struct S, char2),
 eLONG1 = offsetof(struct S, long1),
} PARAMETER_ID;

char GetChar(int para_id)
{
  return *((char*)((char *)&myStruct + para_id));
}

int GetInt(int para_id)
{
  return *((int*)((char *)&myStruct + para_id));
}

long GetLong(int para_id)
{
  return *((long*)((char *)&myStruct + para_id));
}

void main(void)
{
  printf("offsetof int1  = %d\n", eINT1);
  printf("offsetof char1 = %d\n", eCHAR1);
  printf("offsetof int2  = %d\n", eINT2);
  printf("offsetof char2 = %d\n", eCHAR2);
  printf("offsetof long1 = %d\n", eLONG1);


  printf("int1  = %d\n",  GetInt (eINT1));
  printf("char1 = %c\n",  GetChar(eCHAR1));
  printf("int2  = %d\n",  GetInt (eINT2));
  printf("char2 = %c\n",  GetChar(eCHAR2));
  printf("long1 = %ld\n", GetLong(eLONG1));
}
于 2013-02-18T09:01:53.387 に答える
2

あなたは部分的にあなた自身の質問に答えます、offsetofまさにこの目的のために使用されることを意図しています. 構造体のパディング/アライメントを考慮する必要があります。これに似たものを探していると思います:

#include <stddef.h>  // size_t, offsetof
#include <string.h>  // memcpy
#include <stdio.h>

typedef struct
{
  int  int1;
  char char1;
  int  int2;
  int  int50;
} myStruct;

typedef enum
{
  eINT1,
  eCHAR1,
  eINT2,
  eINT50,
  ITEMS_IN_STRUCT
} myEnum;


static const size_t MYSTRUCT_MEMBER_OFFSET [ITEMS_IN_STRUCT] =
{
  offsetof(myStruct, int1),
  offsetof(myStruct, char1),
  offsetof(myStruct, int2),
  offsetof(myStruct, int50),
};

static const myStruct MS;
static const size_t MYSTRUCT_MEMBER_SIZE [ITEMS_IN_STRUCT] = 
{
  sizeof(MS.int1),
  sizeof(MS.char1),
  sizeof(MS.int2),
  sizeof(MS.int50)
};



void myStruct_get_member (void* result, const myStruct* ms, myEnum id)
{
  memcpy (result, 
          (char*)ms + MYSTRUCT_MEMBER_OFFSET[id], 
          MYSTRUCT_MEMBER_SIZE[id]);
}
于 2013-02-18T07:59:47.923 に答える