C 字典/地图

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)

Chr*_*utz 5

我怀疑你(理想情况下)想要的是一本字典:

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_strfrom_str功能需要一些更宏观弄虚作假实现自动化。为此,您可能需要查看 P99。from_abv对于一般情况,我不建议使用该函数,因为我们无法保证下次创建可迭代字段时会使用带下划线的名称。(当然,您可以删除该from_abv函数并为您的成员提供诸如SP,TL和 之类的难以理解的名称SR,这样您就可以直接将它们与您的字符串数据进行比较,但是您需要将 the 更改strcmp为 a memcmp,参数为(sizeof(#x) - 1)。然后所有的您可以from_abv使用的地方from_str,可以为您自动生成。)

但是,from_abv不难定义,老实说,您可以将您的if块从上面复制并粘贴到其中 - 它会稍微高效一点,但如果您添加了“成员”,则必须更新该功能(如写,如果您添加成员,它会自行更新。)