Les*_*sto 5 c pointers structure void-pointers
我想用C语言编写(没有特别的味道,比方说c11)一个通用的全局const数组结构,如下面的伪代码:
void * generic[] ={&(struct a va),&(struct b vb)};
Run Code Online (Sandbox Code Playgroud)
现在我想创建一个函数,给定所需结构的位置的id(我打算为每个id使用const,硬编码),将复制它.
因为那copy()也是通用的(接受一个void *目的地),它需要知道严格的大小,可能由调用者指定(很多容易出错,他已经需要提供目标结构和正确的id)或者我也会sizeof为每个结构维护一个正确的并行数组.
有没有办法在编译时自动化sizeof数组的初始化?或者甚至实现某种技巧让用户指定只是将指针传递给没有id的struct,而不必编写专门的get_struct_x()?
不允许动态分配(alloc(),局部变量很好),所有struct和generic数组内容在编译时都是已知的.
对不起我的错误解释,随时改进/纠正它.
编辑以澄清:我需要从存储了许多结构类型的数组深层复制已知的结构类型,但相同的类型永远不会重复.我需要从一个通用的get函数中执行它将从不同的线程调用,因此在复制之前和之后将锁定一个互斥锁,并且我希望将所有锁定和转换代码保存在一个点上,以最小化调试和创建更有效的测试.
我的一个没有 stackoverflow 帐户的朋友(@Francesco)重新阐述了 @WhozCraig 的答案,添加了(非常旧的)X 宏(感谢Randy Meyers 的精彩文章)来构建通用结构数组并且枚举有助于访问数组的结构,使用户只能编辑一个位置;
回去工作时我告诉他我想尝试制作特定的结构吸气剂(因为数组中不会有重复的结构类型。如果你弄错了,编译时错误,所以在一天结束时开发时你会低头,但一旦编译它就会更健壮),所以我们会对请求的结构体的类型进行编译检查;回到家他就已经实施了。荣誉!
然后,我又在这方面浪费了一些时间,并让开发人员只需输入一次结构,以防止那一侧出现错位;这是优化螺旋的开始;
GENERIC_TABLE和结构定义GENERIC_TABLE工作正常,将其移至外部标头以增加可读性成本
TL;DR:这里是完整的编译代码和基本示例:
#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;
}
Run Code Online (Sandbox Code Playgroud)