Array of structure and size

I want to write in C (there is no particular taste, say, c11) for a general global struct struct array, such as the following pseudocode:

void * generic[] ={&(struct a va),&(struct b vb)}; 

Now I want to create a function that, given the position identifier of the desired structure (I plan to use a constant for each id, hardcoded), will copy it.

Since this copy() also generic (accepts void * as the destination), it will need to know the strict size that the caller can specify (many errors, it should already provide the target structure and the right id) or I will also support parallel an array of the correct sizeof for each structure.

Is there a way to automate the sizeof array initialization during compilation? Or even implement some kind of trick to instruct the user to simply pass a pointer to a struct without its identifier, without creating a specialized get_struct_x() ?

No dynamic allocation ( alloc() , local variable in order) is allowed, all contents of the structure and the general array are known at compile time.

Sorry for my poor explanation, feel free to improve / fix it.

Edit for clarification: I need to deeply copy the know structure type from the array where many struct types are stored, but the same type is never repeated. And I need to do this from the universal get function, which will be called from another thread, so the mutex is blocked before and after copying, and I want to save all the lock and cast code at one point in order to minimize debugging and create a more efficient test.

+5
source share
3 answers

my friend [s] without a stackoverflow account [/ s] (@Francesco) reworked @WhozCraig's answer by adding a (very old) X macro (thanks to a great article from Randy Meyers) to build a general array of struct AND enum witch help to access to the struct array, leaving the user to edit only one place;

Returning to work, I told him that I would like to try to create a specific getter object (since there will be NO REPEATED TYPE OF STRUCTURE in the array. If you make a mistake, copy the time error, so at the end of the day when you bow your head during development , but after compilation it will be more reliable), so we will have a compilation check of the type of the requested structure; back he already implemented it. KUDOS!

Then again, I lost some time on it and will make the developer just have to type one time in the structure to prevent displacement from this side; it was the beginning of an optimization spiral,

  • due to specialized get and put, a dimensional array is no longer required, therefore the general structure is removed
  • no initialized structure is required, we use anonymous structure initialization
  • because "anonymous" initialization, it’s more difficult to directly access the structure
  • direct access requires knowledge of the system, which leads to awareness.
  • the code is more readable
  • Easily export GENERIC_TABLE and structure definitions to an external independent file
  • #ifdef on GENERIC_TABLE works fine, move it to the outer header to increase readability.
  • no dynamic initialization required outside the local variable (no garbage built into the user-friendly interface)
  • extremely easy to use

Cost

  • Perhaps a little preprocessor was swollen?
  • it seems a lot of OOP xD
  • you can call get and put with an uninitiated pointer

TL DR: here is the full compilation code and a basic example:

 #include <memory.h> #include <stdio.h> #include <stdlib.h> /* BEGIN: just some struct to test, fell free to move them on external header file */ struct A { int a1; long a2; }; struct B { float b1; char b2[6]; }; struct C { unsigned int c1; double c2[5]; }; /* END: just some struct to test, fell free to move them on external header file */ /* this macro will create the right X macro element, and also initiliaze the "anonymous" struct */ #define ADD_STRUCT_TO_ARRAY(xu) X(xu, &(struct xu){})SEP /* BEGIN: add or remove your own struct here! * fell free to move them on external header file * just need to pass struct name without "struct" to ADD_STRUCT_TO_ARRAY macro */ #define GENERIC_TABLE \ ADD_STRUCT_TO_ARRAY(A) \ ADD_STRUCT_TO_ARRAY(B) \ ADD_STRUCT_TO_ARRAY(C) /* END: add or remove your own struct here! */ /* here we initialize the enum, where the type of the struct is the key, and its position in the array the value */ #define SEP , #define X(a,b) a enum STRUCT { GENERIC_TABLE }; #undef X /* here we initalize the array of pointer to the structure */ #define X(a,b) b void * const generic[] = { GENERIC_TABLE }; #undef X #undef SEP /* here we create all the getter function. add here your array locking code */ #define SEP ; #define X(a,b) void get_##a(struct a * dest){memcpy(dest, generic[a], sizeof(struct a) );} GENERIC_TABLE #undef X #undef SEP /* here we create all the putter function. add here your array locking code */ #define SEP ; #define X(a,b) void put_##a(struct a * source){memcpy(generic[a], source, sizeof(struct a) );} GENERIC_TABLE #undef X #undef SEP /*run, code, run!*/ int main() { struct A a_copy; struct B b_copy; struct C c_copy; get_A(&a_copy); get_B(&b_copy); get_C(&c_copy); printf("STRUCTURE IN ARRAY BEFORE INITIALIZATION\n"); printf("A = %d\n", a_copy.a1); printf("B = %f\n", b_copy.b1); printf("C = %x\n", c_copy.c1); a_copy.a1 = -1; b_copy.b1 = 2.3; c_copy.c1 = 3; printf("STRUCTURE CHANGED TO\n"); printf("A = %d\n", a_copy.a1); printf("B = %f\n", b_copy.b1); printf("C = %x\n", c_copy.c1); printf("STRUCTURE SAVED\n"); put_A(&a_copy); put_B(&b_copy); put_C(&c_copy); get_A(&a_copy); get_B(&b_copy); get_C(&c_copy); printf("STRUCTURE LOADED\n"); printf("A = %d\n", a_copy.a1); printf("B = %f\n", b_copy.b1); printf("C = %x\n", c_copy.c1); a_copy.a1 = 1000; b_copy.b1 = -50.576; c_copy.c1 = 700; printf("STRUCTURE CHANGED TO\n"); printf("A = %d\n", a_copy.a1); printf("B = %f\n", b_copy.b1); printf("C = %x\n", c_copy.c1); get_A(&a_copy); get_B(&b_copy); get_C(&c_copy); printf("STRUCTURE RELOADED WITHOUT SAVING\n"); printf("A = %d\n", a_copy.a1); printf("B = %f\n", b_copy.b1); printf("C = %x\n", c_copy.c1); return 0; } 
+1
source

Without the need to change the underlying data structures, this is the only method I can see where it will be sufficiently manageable. Each entry in your array is not void* , but rather a structure that contains void* (for an element) and size_t (sizeof data for that element):

 #include <stdio.h> #include <stdlib.h> typedef struct Entry { size_t len; void const *elem; } Entry; #define ELEM_ENTRY(x) { sizeof(x), &(x) } struct A { int a1; long a2; } a; struct B { float b1; char b2[6]; } b; struct C { unsigned int c1; double c2[5]; } c; Entry generic[] = { ELEM_ENTRY(a), ELEM_ENTRY(b), ELEM_ENTRY(c) }; size_t generic_n = sizeof(generic)/sizeof(*generic); int main() { for (size_t i=0; i<generic_n; ++i) printf("[%zu] = %zu\n", i, generic[i].len); } 

Exit

 [0] = 8 [1] = 12 [2] = 44 

I think what you are trying to do. if not, I will drop this answer. Note that this will most likely not work the way you want if the element is a pointer type (but it will work the way you want if it is a native array type). So be careful.

+3
source

I would make the size of the structure the first element in each structure. So you have

 struct a { size_t size; int a1; double a2; // ... }; struct b { size_t size; char b1[20]; float b2; // ... }; 

Each time you create a structure, be sure to initialize the size, for example.

 struct a *aptr = malloc( sizeof(struct a) ); aptr->size = sizeof(struct a); aptr->a1 = 3; aptr->a2 = 100.5; struct b someB = { sizeof(struct b), "hello", 1.0 }; 

Then in the copy routine, you can specify void * in size_t * to get the size of the structure, since you know that each structure will be sized as the first element.

0
source

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


All Articles