从C中获取一个大结构的子结构

Ela*_*ich 3 c struct bit-fields data-structures

struct现有的计划非常重要.该结构包括大量的位域.

我希望保存它的一部分(例如,150个中的10个字段).

我用来保存子类的示例代码是:

typedef struct {int a;int b;char c} bigstruct;
typedef struct {int a;char c;} smallstruct;
void substruct(smallstruct *s,bigstruct *b) {
    s->a = b->a;
    s->c = b->c;
}
int save_struct(bigstruct *bs) {
    smallstruct s;
    substruct(&s,bs);
    save_struct(s);
}
Run Code Online (Sandbox Code Playgroud)

我也希望选择它的哪一部分不会太麻烦,因为我希望时不时地改变它.我之前介绍的天真的方法是非常脆弱和不可维护的.当扩展到20个不同的字段时,您必须更改smallstruct和在substruct函数中的字段.

我想到了两种更好的方法.不幸的是,两者都要求我使用一些外部的CIL工具来解析我的结构.

第一种方法是自动生成substruct函数.我只是设置结构smallstruct,并有一个程序可以解析它并substruct根据中的字段生成函数smallstruct.

第二种方法是构建(使用C解析器)关于的元信息bigstruct,然后编写一个允许我访问结构中特定字段的库.这就像Java的类反射的临时实现.

例如,假设没有struct-alignment,对于struct

struct st {
    int a;
    char c1:5;
    char c2:3;
    long d;
}
Run Code Online (Sandbox Code Playgroud)

我将生成以下元信息:

int field2distance[] = {0,sizeof(int),sizeof(int),sizeof(int)+sizeof(char)}
int field2size[] = {sizeof(int),1,1,sizeof(long)}
int field2bitmask[] =  {0,0x1F,0xE0,0};
char *fieldNames[] = {"a","c1","c2","d"};
Run Code Online (Sandbox Code Playgroud)

我将使用此功能获得第ith个字段:

long getFieldData(void *strct,int i) {
    int distance = field2distance[i];
    int size = field2size[i];
    int bitmask = field2bitmask[i];
    void *ptr = ((char *)strct + distance);
    long result;
    switch (size) {
        case 1: //char
             result = *(char*)ptr;
             break;
        case 2: //short
             result = *(short*)ptr;
        ...
    }
    if (bitmask == 0) return result;
    return (result & bitmask) >> num_of_trailing_zeros(bitmask);
 }
Run Code Online (Sandbox Code Playgroud)

这两种方法都需要额外的工作,但是一旦解析器在你的makefile中 - 改变子结构是一件轻而易举的事.

但是,我宁愿这样做,没有任何外部依赖.

有没有人有更好的主意?我的想法有什么好处,我的想法在互联网上是否可以实现?

Ran*_*pho 12

根据您的描述,您可以访问并修改原始结构.我建议你将子结构重构成一个完整的类型(就像在你的例子中所做的那样),然后在你的大结构上将该结构作为一个字段,将原始结构中的所有字段封装到较小的结构中.

扩展您的小例子:

typedef struct 
{
  int a;
  char c;
} smallstruct;

typedef struct 
{
  int b;
  smallstruct mysub;
} bigstruct;
Run Code Online (Sandbox Code Playgroud)

访问smallstruct信息将如下所示:

/* stack-based allocation */
bigstruct mybig;
mybig.mysub.a = 1;
mybig.mysub.c = '1';
mybig.b = 2;

/* heap-based allocation */
bigstruct * mybig = (bigstruct *)malloc(sizeof(bigstruct));
mybig->mysub.a = 1;
mybig->mysub.c = '1';
mybig->b = 2;
Run Code Online (Sandbox Code Playgroud)

但你也可以传递指向小结构的指针:

void dosomething(smallstruct * small)
{ 
  small->a = 3;
  small->c = '3';
}

/* stack based */    
dosomething(&(mybig.mysub));

/* heap based */    
dosomething(&((*mybig).mysub));
Run Code Online (Sandbox Code Playgroud)

优点:

  • 没有宏
  • 没有外部依赖
  • 没有内存订单投射黑客
  • 更清洁,更易于阅读和使用代码.