ç词典/图 [英] C dictionary/map

查看:79
本文介绍了ç词典/图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要结构成员映射,所以我可以,如果分支机构在一个循环中消除。什么是用C来实现这一点的最好办法还是约定?我想这可能是一个2维数组,而不是...然后我可以整数映射到字符键?

 字符块[32];
    INT N;
    INT I;
    字符* PTR =配置;
    而(* PTR!='\\ 0'){
        INT items_read =的sscanf(PTR,%31 [^;]%N,大块,与安培; N);        如果(组块[0] =='S'和放大器;&放大器;组块[1] ==P){
            对于(i = 0; I< GLOBAL_MEAS_CUTOFF;我++){
                theMeas [I] .signal_path =与atoi(安培;组块[2]);
            }
        }
        如果(块[0] =='T'和;&安培;块[1] =='L'){
            对于(i = 0; I< GLOBAL_MEAS_CUTOFF;我++){
                theMeas [I] .trace_length =与atoi(安培;组块[2]);
            }
        }
        如果(组块[0] =='S'和放大器;&放大器;组块[1] =='R'){
            对于(i = 0; I< GLOBAL_MEAS_CUTOFF;我++){
                theMeas [I] .sample_rate =与atoi(安培;组块[2]);
            }
        }        块[0] ='\\ 0';
        如果(items_read == 1)
            PTR + = N;
        如果(* PTR =';'){
            打破;
        }
        ++ PTR;
    }


解决方案

我怀疑你(理想)想要的是一个字典:

  theMeas [I] [signal_path] =的atoi(安培;块[2]);

当然,上面的语法永远不会用C发生,但在这里,这不是真的很重要。问题是,你会写所有code实现一个字典数据类型,我怀疑这是矫枉过正。

所以我怀疑你(真正)需要的是一种方法,有一个可以在循环中使用的名称:

 的foreach(signal_path,trace_length,SAMPLE_RATE)

和我在这里要告诉你,你可以做到这一点(种)!最简单的方法是使用枚举

 枚举领域{
  signal_path,
  trace_length,
  采样率,
  END_fields,
  UNKNOWN_fields,
  BEGIN_fields = 0,
};

而不是结构的成员,您可以使用一个数组:

  INT theMeas [大小] [END_fields];

要指数成员,用这个:

  theMeas [I] [signal_path];

您可以通过所有的循环的成员,你可以用这样的:

 为(枚举场j = BEGIN_fields;!J = END_fields; J ++)
    theMeas [I] [J]。

这也打破了一点,当你想获得基于字符的比较,但我们可以做一点点:

 为const char * to_str(枚举域F)
{
#定义FIELD(x)的情况下,X:回归#X
    开关(F)
      {
        FIELD(signal_path);
        FIELD(trace_length);
        FIELD(SAMPLE_RATE);
        默认:回归<&不明GT;
      }
和#undef场
}枚举域from_str均被(为const char * C)
{
#定义FIELD(x)如果(!STRCMP(C,#X))返回X
        FIELD(signal_path);
        FIELD(trace_length);
        FIELD(SAMPLE_RATE);
        默认:回归UNKNOWN_fields;
和#undef场
}枚举域from_abv(字符* C)
{
    对于(枚举场I = BEGIN_fields; I< END_fields;我++)
      {
        字符*字段=栏位字串(我);
        如果(tolower的(C [0])==字段[0]&放大器;&放大器; tolower的(三[1])==和strchr(场,_)[1])
            返回我;
      }
    返回UNKNOWN_fields;
}

如果语句可以替换为:

  theMeas [I] [from_abv(块)] =的atoi(安培;块[2]);

或者,更安全:

 枚举场j = from_abv(块);
如果(!J = UNKNOWN_fields)theMeas [I] [j]的=的atoi(安培;组块[2]);
否则/ *错误的用户输入* /;

这是最接近我能得到的。

请注意,我已经特意用一个命名方案,以促进宏的创建,将自动执行大部分的这一点。让我们尝试:

 的#define成员(姓名,...)\\
  枚举名{__VA_ARGS__,\\
              M_END _ ##名,\\
              M_UNKNOWN _ ##名,\\
              M_BEGIN _ ##名= 0}#定义斜切(姓名,VAR)\\
        枚举名VAR = M_BEGIN _ ##名; VAR = M_END _ ##名!; VAR ++#定义MSIZE(名称)M_END _ ##名

用法:

  //定义我们的田野
成员(字段,signal_path,trace_length,SAMPLE_RATE);//声明对象,领域
INT theMeas [N] [MSIZE(场)];用于(为size_t我= 0; I< N;我++)
    //迭代领域
    对于(斜切(字段,J))
        //对阵领域
        如果(J == from_abv(块))
            theMeas [I] [j]的=的atoi(安培;组块[2]);

这是最后一点似乎并没有那么糟糕。它仍然可以让你接近的东西结构式的访问通过 theMeas [I] [signal_path] ,但允许您遍历成员,并隐藏了大部分宏背后繁重的工作。

to_str from_str均被函数需要一点更为宏观的挂羊头卖狗肉实现自动化。你可能需要寻找到P99为。在 from_abv 的功能是不是我推荐的一般情况下,我们没有办法保证的,下次你做迭代的领域,你将使用其名称下划线。 (当然,你可以删除 from_abv 功能,让你的会员高深莫测的名称,如 SP TL SR ,允许你直接把它们比作你的字符串数据,但你需要修改 STRCMP memcmp (的sizeof(#X) - 1)。然后所有的地方,你有 from_abv 你只需要使用 from_str均被,它可以为你自动生成。)

然而, from_abv 不是很难界定,你可以诚实地复制并粘贴如果块从上面到它 - 它会稍微更有效,但如果你增加了一个成员你必须更新的功能(如写的,它会如果你添加一个成员自我更新)

I want to map struct members so I can eliminate if branches in a loop. What is the best way or convention to implement this in C? I suppose it could be a 2 dimensional array instead...then I could map integers to the char keys?

    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;
    }

解决方案

I suspect what you (ideally) want is a dictionary:

theMeas[i]["signal_path"] = atoi(&chunk[2]);

Of course, the above syntax will never happen in C, but that's not really important here. The problem is that you would have to write all the code implementing a dictionary data type, and I suspect that's overkill.

So I suspect what you (really) want is a way to have names that can be used in a loop:

foreach(signal_path, trace_length, sample_rate)

And I'm here to tell you that you can do this (kind of)! The simplest way is with an enum:

enum fields {
  signal_path,
  trace_length,
  sample_rate,
  END_fields,
  UNKNOWN_fields,
  BEGIN_fields = 0,
};

Instead of struct members, you use an array:

int theMeas[size][END_fields];

To index a "member", use this:

theMeas[i][signal_path];

You can loop through all the "members," you can use this:

for(enum fields j = BEGIN_fields; j != END_fields; j++)
    theMeas[i][j];

This does break down a little when you want to get character-based comparisons, but we can do a little bit:

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;
}

Your if statements could be replaced with:

theMeas[i][from_abv(chunk)] = atoi(&chunk[2]);

Or, more safely:

enum fields j = from_abv(chunk);
if(j != UNKNOWN_fields) theMeas[i][j] = atoi(&chunk[2]);
else /* erroneous user input */;

Which is about as close as I can get.

Note that I've deliberately used a naming scheme to facilitate the creation of macros that will automate much of this. Let's try:

#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

Usage:

// 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]);

That last bit doesn't seem so bad. It still allows you something close to struct-like access via theMeas[i][signal_path], but allows you to iterate over the "members," and hides most of the heavy lifting behind macros.

The to_str and from_str functions take a little more macro trickery to automate. You'll probably need to look into P99 for that. The from_abv function isn't something I'd recommend for the general case, as we have no way of guaranteeing that the next time you make iterable fields you'll use names with underscores. (Of course, you could drop the from_abv function and give your members inscrutable names like SP, TL, and SR, allowing you to directly compare them to your string data, but you'd need to change the strcmp to a memcmp with a size argument of (sizeof(#x) - 1). Then all the places you have from_abv you'd just use from_str, which can be automatically generated for you.)

However, from_abv isn't hard to define, and you could honestly just copy and paste your if blocks from above into it - it'd be slightly more efficient, though if you added a "member" you'd have to update the function (as written, it'll update itself if you add a member.)

这篇关于ç词典/图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆