我甚至都不知道,我所问的是不是愚蠢与否。我不是要求你为我编写任何代码,而是要以更好的方式做一些事情。
我有一个包含大量项目的结构:
typedef struct _myStruct
{
int int1;
char char1;
int int2;
:
:
int int50;
}myStruct;
我有另一个枚举,它对myStruct中的每个项目都有一个条目。
enum
{
eINT1,
eCHAR1,
eINT2,
:
:
eINT50
} PARAMETER_ID;
我想为每种数据类型编写一个函数[比如一个用于int,一个用于char,一个用于字符串等],当myStruct
时,它返回PARAMETER_ID
成员的值作为输入。
例如,我需要一个int GetInt(PARAMETER_ID)
函数,当eINT1作为参数传递时,该函数返回int1
的值。同样地,我将有char GetCharacter(PARAMETER_ID)
,float GetFloat(PARAMETER_ID)
等。
结构中的项目数可能很大。因此,为每个项目使用开关盒将不是一个可行的选择。
我能想到的其他选项是使用结构变量的地址和offsetof()
函数来计算参数的地址,然后通过memcpy
将所需的字节变成变量。在这种情况下,我需要在每个地方保留每个参数的偏移量,但这不是问题。
我正在寻找替代方案来做到这一点。任何帮助将不胜感激。
谢谢。
答案 0 :(得分: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
并且不想玩这样的技巧)您可能会考虑制作GCC扩展程序MELT(扩展GCC的高级域专用语言)可以帮助您;您可能可以进行MELT扩展以为您生成访问器功能。
您还可以说服您的老板从特定描述性文件中生成struct
,enum
和访问者函数(使用awk
,python
或随你)。 GCC为其选项文件执行此类操作,例如: gcc/common.opt
最后,如果包含_myStruct
的标题是如此神圣,以至于您不允许触摸它,并且如果格式非常干净,您可以进行临时(例如awk
)脚本来获取声明并处理它。
NB一个好的编译器将密集switch
语句优化为索引跳转,这需要花费一些时间,即使是数百个情况。
答案 1 :(得分: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));
}
答案 2 :(得分:1)
您部分回答了自己的问题,offsetof
旨在用于此目的。你必须考虑struct padding / alignment。我想你正在寻找类似的东西:
#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]);
}