Getting a substring from a large structure in C

I have a very large one structin the existing program. This structure includes a large number of bitfields.

I want to save part of it (say, 10 fields out of 150).

The sample code that I would use to save the subclass is as follows:

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

I also want to choose which part of it will not be too complicated, since I want to change it from time to time. The naive approach that I presented earlier is very fragile and unattainable. When scaling to 20 different fields, you must change the fields in both the smallstructfunction and the function substruct.

I thought of two best approaches. Unfortunately, both require me to use an external CIL as a tool to analyze my structures.

substruct. smallstruct , substruct smallstruct.

( C parser) bigstruct, , . ad-hoc Java.

, , struct

struct st {
    int a;
    char c1:5;
    char c2:3;
    long d;
}

:

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

i th :

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

, makefile - - .

- .

- ? , - ?

+3
5

, bigstruct , smallstruct , (, ). - :

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

int save_struct(bigstruct *bs) {
    save_struct((smallstruct *)bs);
}
+3

, , . ( ), , .

:

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

typedef struct 
{
  int b;
  smallstruct mysub;
} bigstruct;

:

/* 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;

:

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

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

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

:

  • , .
+11

- .

include, .

, , , BEGIN_STRUCTURE, END_STRUCTURE, NORMAL_FIELD, SUBSET_FIELD

, . , . , NORMAL_FIELD . .

, , , .

+1

, offsetof(), ,

0

:

  • , . .
  • , - ( - )
  • , . , - .
  • ( ).
  • C, createSubStruct,
  • , emit ss.field = bs.field (.. ).
  • make C

gawk , , ; , .

[EDIT] ( , , C), offsetof() - . ( ). . .

[EDIT2] . , ; , . , , , , , : C. , :

struct big_struct {
    /**BEGIN_COPY*/
    int i;
    int j : 3;
    int k : 2;
    char * str;
    /**END_COPY*/
    ...
    struct x y; /**COPY_STRUCT*/
}

/**BEGIN_COPY*/ /**END_COPY*/.

, /**COPY_STRUCT*/, memcpy() ..

This can be recorded and debugged in a few hours. It will take so long to configure the parser for C without any functionality; that is, you only have something that can read real C, but you still have to write a part of the parser that understands C, and a part that does something useful with the data.

0
source

Source: https://habr.com/ru/post/1708657/


All Articles