2014-09-23 194 views
5

我想写点什么,在C(无particolar味,可以说C11)结构的通用,全球常量数组,如下面的伪代码:阵列的结构和sizeof

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

现在我想创建一个函数,给定所需结构的位置id(我打算为每个id使用const,硬编码),将复制它。

因为copy()也是通用的(接受一个void *作为目的地),它需要知道严格的大小,女巫可能由调用者指定(很多错误倾向,他已经需要提供目标结构和权利ID)或者我还会为每个结构维护一个正确的sizeof平行阵列。

有没有办法在编译时自动化sizeof数组的初始化?或者甚至实现一些技巧,让用户指定只传递指针结构没有它的ID,而不必写一个专门的get_struct_x()

不允许动态分配(alloc(),局部变量很好),所有结构和通用数组内容在编译时已知。

对不起,我的不好解释,随时改善/纠正它。

编辑澄清:我需要深入复制一个知道结构类型从一个数组存储很多结构类型,但相同的类型不会重复自己。而且我需要从一个通用的get函数中完成,这个函数将从不同的线程中调用,所以在复制之前和之后都会锁定一个互斥量,并且我希望将所有的锁定和转换代码保留在一个点上,从而最大限度地减少调试并创建更有效的测试。

+0

我觉得你的问题是,“我可以写一个函数,它需要一个'struct'和一个索引和'struct'目标地址作为输入 - 这样特定的'struct'被绑定'别的地方'?” – 2014-09-23 22:06:35

+1

“有没有办法在编译时自动化sizeof数组的初始化?”唯一可用的机制是预处理器。这是抽象这种功能最常用的工具。 – 2014-09-23 22:07:13

+0

是否可以将每个结构的大小存储在它自己内部?即,在每个结构中添加一个成员int mySize作为第一个成员,并将它(在运行时)设置为'x.mySize = sizeof(struct x)'。 – usr2564301 2014-09-23 22:09:36

回答

1

矿[S]没有计算器的帐户[/ S](@Francesco)的朋友已经重新阐述了@WhozCraig答案(由兰迪·迈尔斯感谢great article)将(很老)X macro打造通用结构数组和枚举女巫有助于访问数组的结构,让用户只编辑一个点;

回到工作我告诉过他,我想尝试使特定的结构getter(因为在数组中没有REPEATED STRUCT TYPE,如果你弄错了,编译时错误,所以在当你在开发的时候你会弯下腰,但是一旦编译它就会更加健壮),所以我们将对所请求的结构的类型进行编译检查; 回到家他已经实施了。奖励!

然后我又失去了一些时间,使开发人员只需键入一次结构,以防止在那一侧的错位; 这已经是优化螺旋的开始;

  • 因为专门get和put,不再需要大小排列的,所以删除了通用的结构
  • 没有初始化的结构需要,我们使用“匿名”结构初始化
  • 因为“匿名”初始化,它是很难直接访问结构
  • 直接访问需要的知识体系,有导致意识
  • 代码的可读性更强
  • 容易导出GENERIC_TABLE和外部独立的文件结构定义
  • #ifdef的GENERIC_TABLE正常工作,将其移动到外部头以增加可读性
  • 外局部变量不需要动态初始化(无垃圾,嵌入型)
  • 使用极为方便

成本

  • 也许有点臃肿预处理器?
  • 看来很多OOP的xD
  • 可以拨打得到与外行指针

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

我会使结构的大小成为每个结构中的第一个元素。所以你有

struct a 
{ 
    size_t size; 
    int a1; 
    double a2; 
    // ... 
}; 

struct b 
{ 
    size_t size; 
    char b1[20]; 
    float b2; 
    // ... 
}; 

任何时候你创建一个结构,一定要初始化大小,例如,

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

然后,在拷贝过程中,您可以施放void *size_t *得到结构的大小,因为你知道,每一个结构会具有尺寸为第一要素。

+0

我一般喜欢这种方法比其他两个答案更好,但不幸的是,OP明确指出,'的malloc()'是不允许的解。因此,没有+1 :-( – cmaster 2014-09-24 19:24:49

3

无需修改底层的数据结构,这是我可以看到这将是相当易于管理的唯一方法。阵列中的每个条目是一个void*,而是包含一个void*(向元件)的结构体和一个size_t(该元素的sizeof数据):

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

输出

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

认为这就是你想要做的。如果没有,我会放弃这个答案。请注意,这可能会而不是如何工作,如果元素是指针类型(但它工作如何,如果它是本机阵列类型)。所以要小心。

+0

遗憾地删除您accepeted的答案,但看到我自己的答案使用X宏做一些更多的技巧 – Lesto 2014-09-24 19:15:52