eat*_*mon 1 c struct hashtable hashmap
我想映射结构成员,这样我就可以消除循环中的分支。在 C 中实现它的最佳方法或约定是什么?我想它可能是一个二维数组......然后我可以将整数映射到字符键?
char chunk[32];
int n;
int i;
char *ptr = config;
while (*ptr != '\0') {
int items_read = sscanf(ptr, "%31[^;]%n", chunk, &n);
if(chunk[0] == 'S' && chunk[1] == 'P') {
for(i=0;i<GLOBAL_MEAS_CUTOFF; i++) {
theMeas[i].signal_path = atoi(&chunk[2]);
}
}
if(chunk[0] == 'T' && chunk[1] == 'L') {
for(i=0;i<GLOBAL_MEAS_CUTOFF; i++) {
theMeas[i].trace_length = atoi(&chunk[2]);
}
}
if(chunk[0] == 'S' && chunk[1] == 'R') {
for(i=0;i<GLOBAL_MEAS_CUTOFF; i++) {
theMeas[i].sample_rate = atoi(&chunk[2]);
}
}
chunk[0]='\0';
if (items_read == 1)
ptr += n;
if ( *ptr != ';' ) {
break;
}
++ptr;
}
Run Code Online (Sandbox Code Playgroud)
我怀疑你(理想情况下)想要的是一本字典:
theMeas[i]["signal_path"] = atoi(&chunk[2]);
Run Code Online (Sandbox Code Playgroud)
当然,上述语法在 C 中永远不会发生,但这在这里并不重要。问题是您必须编写实现字典数据类型的所有代码,我怀疑这太过分了。
所以我怀疑你(真正)想要的是一种可以在循环中使用的名称的方法:
foreach(signal_path, trace_length, sample_rate)
Run Code Online (Sandbox Code Playgroud)
我在这里告诉你你可以做到这一点(有点)!最简单的方法是使用enum:
enum fields {
signal_path,
trace_length,
sample_rate,
END_fields,
UNKNOWN_fields,
BEGIN_fields = 0,
};
Run Code Online (Sandbox Code Playgroud)
struct您使用数组而不是成员:
int theMeas[size][END_fields];
Run Code Online (Sandbox Code Playgroud)
要索引“成员”,请使用以下命令:
theMeas[i][signal_path];
Run Code Online (Sandbox Code Playgroud)
你可以遍历所有的“成员”,你可以使用这个:
for(enum fields j = BEGIN_fields; j != END_fields; j++)
theMeas[i][j];
Run Code Online (Sandbox Code Playgroud)
当您想要进行基于字符的比较时,这确实会有所分解,但我们可以做一点:
const char *to_str(enum fields f)
{
#define FIELD(x) case x: return #x
switch(f)
{
FIELD(signal_path);
FIELD(trace_length);
FIELD(sample_rate);
default: return "<unknown>";
}
#undef FIELD
}
enum fields from_str(const char *c)
{
#define FIELD(x) if(!strcmp(c, #x)) return x
FIELD(signal_path);
FIELD(trace_length);
FIELD(sample_rate);
default: return UNKNOWN_fields;
#undef FIELD
}
enum fields from_abv(char *c)
{
for(enum fields i = BEGIN_fields; i < END_fields; i++)
{
char *field = field_str(i);
if(tolower(c[0]) == field[0] && tolower(c[1]) == strchr(field, '_')[1])
return i;
}
return UNKNOWN_fields;
}
Run Code Online (Sandbox Code Playgroud)
您的if陈述可以替换为:
theMeas[i][from_abv(chunk)] = atoi(&chunk[2]);
Run Code Online (Sandbox Code Playgroud)
或者,更安全:
enum fields j = from_abv(chunk);
if(j != UNKNOWN_fields) theMeas[i][j] = atoi(&chunk[2]);
else /* erroneous user input */;
Run Code Online (Sandbox Code Playgroud)
这是我能得到的最接近的。
请注意,我特意使用了命名方案来促进宏的创建,这些宏将自动执行大部分操作。咱们试试吧:
#define member(name, ...) \
enum name { __VA_ARGS__, \
M_END_##name, \
M_UNKNOWN_##name, \
M_BEGIN_##name = 0 }
#define miter(name, var) \
enum name var = M_BEGIN_##name; var != M_END_##name; var++
#define msize(name) M_END_##name
Run Code Online (Sandbox Code Playgroud)
用法:
// define our fields
member(fields, signal_path, trace_length, sample_rate);
// declare object with fields
int theMeas[N][msize(fields)];
for(size_t i = 0; i < N; i++)
// iterate over fields
for(miter(fields, j))
// match against fields
if(j == from_abv(chunk))
theMeas[i][j] = atoi(&chunk[2]);
Run Code Online (Sandbox Code Playgroud)
最后一点似乎并没有那么糟糕。它仍然允许您通过 进行类似struct的访问theMeas[i][signal_path],但允许您迭代“成员”,并隐藏宏背后的大部分繁重工作。
该to_str和from_str功能需要一些更宏观弄虚作假实现自动化。为此,您可能需要查看 P99。from_abv对于一般情况,我不建议使用该函数,因为我们无法保证下次创建可迭代字段时会使用带下划线的名称。(当然,您可以删除该from_abv函数并为您的成员提供诸如SP,TL和 之类的难以理解的名称SR,这样您就可以直接将它们与您的字符串数据进行比较,但是您需要将 the 更改strcmp为 a memcmp,参数为(sizeof(#x) - 1)。然后所有的您可以from_abv使用的地方from_str,可以为您自动生成。)
但是,from_abv不难定义,老实说,您可以将您的if块从上面复制并粘贴到其中 - 它会稍微高效一点,但如果您添加了“成员”,则必须更新该功能(如写,如果您添加成员,它会自行更新。)
| 归档时间: |
|
| 查看次数: |
6708 次 |
| 最近记录: |