C 不使用点运算符访问结构成员
我甚至不知道,我问的是不是愚蠢的问题。我不是要求你为我写任何代码,而是一个以更好的方式做某事的想法 我有一个包含大量如下项的结构:C 不使用点运算符访问结构成员,c,C,我甚至不知道,我问的是不是愚蠢的问题。我不是要求你为我写任何代码,而是一个以更好的方式做某事的想法 我有一个包含大量如下项的结构: typedef struct _myStruct { int int1; char char1; int int2; : : int int50; }myStruct; 我有另一个枚举,它对myStruct中的每个项都有一个条目 enum { eINT1, eCHAR1, eINT2, :
typedef struct _myStruct
{
int int1;
char char1;
int int2;
:
:
int int50;
}myStruct;
我有另一个枚举,它对myStruct中的每个项都有一个条目
enum
{
eINT1,
eCHAR1,
eINT2,
:
:
eINT50
} PARAMETER_ID;
我想为每种数据类型编写一个函数[比如一个用于int,一个用于char,一个用于string等],当参数ID作为输入时,它返回myStruct
的一个成员的值
例如,我需要一个intgetint(PARAMETER\u ID)
函数,当eINT1作为参数传递时,该函数返回int1
的值。类似地,我将使用char-GetCharacter(PARAMETER\u ID)
,float-GetFloat(PARAMETER\u ID)
等
结构中的项目数可能很大。因此,为每个项目使用开关箱将不是一个可行的选择
我能想到的唯一其他选择是使用结构变量的地址和offsetof()
函数来计算参数的地址,然后通过memcpy
将所需的字节输入变量。在这种情况下,我需要将每个参数的偏移量保持在某个位置,但这不是问题
我正在寻找其他的选择来做到这一点。任何帮助都将不胜感激
谢谢。一个大的开关是一个很好的可行选择
您还可以玩预处理器的把戏
您可以有一个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
)
要实现访问器
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/Trime.DEF)
如果你的代码是一个非常大的代码库,并且你准备好花上几天的时间(例如,因为你有很多这样的代码> Stult,不想玩这样的把戏),你可以考虑用一个GCC扩展(一个高级的特定领域的语言来扩展GCC)来帮助你;您可能可以进行MELT扩展来为您生成访问器函数
您还可以说服上司从一个特殊的描述性文件(使用awk
,python
或其他方法)生成struct
、enum
和accessor函数。GCC对其选项文件执行此类操作,例如,GCC/common.opt
最后,如果包含\u myStruct
的标题非常神圣,不允许您触摸它,并且如果它的格式非常干净,您可以制作一个临时脚本(例如awk
)来获取该声明并对其进行处理
注意:一个好的编译器会将密集的switch
语句优化为索引跳转,这需要恒定的时间,即使在数百种情况下也是如此。您可以部分回答自己的问题,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]);
}
#包括//尺寸、偏移量
#包括//memcpy
#包括
类型定义结构
{
int int1;
char-char1;
int int2;
int50;
}我的结构;
类型定义枚举
{
eINT1,
eCHAR1,
eINT2,
eINT50,
结构中的项目
}髓鞘;
静态常量大小\u t MYSTRUCT\u成员\u偏移量[结构中的项目]=
{
偏移量(myStruct,int1),
抵消(我的合同,第1章),
offsetof(myStruct,int2),
偏移量(myStruct,int50),
};
静态常量myStruct MS;
静态常量大小\u t MYSTRUCT\u成员大小[结构中的项目]=
{
sizeof(MS.int1),
sizeof(char1女士),
sizeof(MS.int2),
sizeof(MS.int50)
};
void myStruct\u get\u成员(void*result,const myStruct*ms,myEnum id)
{
memcpy(结果,
(char*)ms+MYSTRUCT成员偏移量[id],
MYSTRUCT_成员_大小[id]);
}
#包括
#包括
结构
{
int int1;
char-char1;
int int2;
char-char2;
龙龙1;
}myStruct={12345,'A',321,'B',-1L};
枚举
{
eINT1=偏移量(结构S,int1),
eCHAR1=偏移量(结构S,字符1),
eINT2=偏移量(结构S,int2),
eCHAR2=偏移量(结构S,字符2),
长度1=偏移量(结构S,长度1),
}参数ID;
char GetChar(int para_id)
{
return*((char*)((char*)&myStruct+para_id));
}
int GetInt(int para_id)
{
返回*((int*)((char*)&myStruct+para_id));
}
long GetLong(int para_id)
{
返回*((长*)((字符*)&myStruct+para_id));
}
真空总管(真空)
{
printf(“int1的偏移量=%d\n”,eINT1);
printf(“字符1的偏移量=%d\n”,eCHAR1);
printf(“int2的偏移量=%d\n”,eINT2);
printf(“字符2的偏移量=%d\n”,eCHAR2);
printf(“长偏移量1=%d\n”,长1);
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));
}
您考虑过阵列吗?使用大型开关是一个很好的可行选择。。。。我相信你拒绝它是错误的…@谢谢。我理解。但我的老板不希望我每次引入新参数时都修改这些函数:(.如果您采用您描述的地址路径,您不需要这样做吗?这些奇怪的结构来自何处?如果您需要以这种方式访问它们,它们是如何以这种方式设计的?@cnicutar:这都是现有代码库的一部分,我不允许修改基本实现,因为它与oth有一些依赖关系呃,代码的一部分。先生,很好。我知道这件事不是那么容易做到。从所有人的评论来看,我认为这个设计很糟糕。所以我正在考虑在老板允许的情况下对设计进行更改,以便我可以
#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]);
}
#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));
}