我有一些以 void *buffer
开头的结构,接下来的成员可以是不同的类型:
struct A {
void *buffer;
type_x *x;
type_y *y;
};
struct B {
void *buffer;
type_w *w;
type_y *y;
type_z *z;
};
struct A
的缓冲区将存储 n 个类型为 type_x
的元素,然后是 n 个类型为 type_y
的元素。其他成员 type_x *x
和 type_y *y
将分别指向这些数组。类似于 struct B
。
我目前正在做的是这样的:
void allocate(struct B **b, unsigned int n) {
(*b)->buffer = calloc(n * (sizeof(type_w) + sizeof(type_y) + sizeof(type_z));
(*b)->w = (type_w *) (*b)->buffer;
(*b)->y = (type_y *) ((*b)->w + n);
(*b)->z = (type_z *) ((*b)->y + n);
}
有没有办法创建一个函数来实现这个?该函数应接收指向这些结构之一的指针 (void *s
) 和一个 int 作为参数,如下所示:
void allocate(void *s, unsigned int n) {
// MAGIC
}
我考虑过的其他一些选项:
创建
void allocate(void *buffer, int n, ...)
并为其提供指向结构指针的指针。这个问题是我必须给它 void * 指针,所以我也必须给它每个类型的大小。Create
void *create_struct(StructType type)
(其中 StructType 是一个枚举)但是无论如何我都必须为每个结构编写案例并且我希望能够定义新结构而不必编写额外的代码。
我正在尝试这样做,因为我将有很多结构,并且因为分配函数对每个结构做的事情基本相同,所以我认为可能有一种“更干净”的方法来做到这一点。
此外,我知道我可以删除缓冲区并直接为所有成员分配内存,但我想这样做以便连续存储数据。
最佳答案
没有一种通用的方法可以做到这一点,同时又不失类型安全性。这意味着,从技术上讲,真正通用的解决方案将导致未定义的行为。如果我被迫实现这样的东西,我将不得不假设我可以将传入的结构指针视为一个指针数组。并且需要传入每种类型的大小。忽略对齐问题,一些未经测试的代码:
void allocate(void *sp, size_t n, ... /* terminate with 0 */) {
void **sv = sp;
size_t arg, total = 0;
size_t args = 0;
va_list ap;
va_start(ap, n);
while ((arg = va_arg(ap, size_t)) != 0) {
total += arg;
++args;
}
va_end(ap);
*sv = calloc(...);
sv[1] = sv[0];
va_start(ap, n);
while (--args > 0) {
++sv;
sv[1] = (char *)sv[0] + va_arg(ap, size_t);
}
va_end(ap);
}
allocate(a, n, sizeof(type_x), sizeof(type_y), (size_t)0);
allocate(b, n, sizeof(type_w), sizeof(type_y), sizeof(type_z), (size_t)0);
明显又黑又丑。
更好的解决方案应该是为每种类型创建一个单独的分配器函数。但是,您可以创建一个宏来帮助自动生成分配器。更多未经测试的代码如下:
#define CREATE_ALLOCATOR(Type, X_Fields) \
void allocate_##Type (struct Type *sp, size_t n) { \
_Pragma("pop_macro(\"X\")") \
size_t total = 0 \
X_Fields \
; \
void *p; \
sp->buffer = calloc(sizeof(*sp) + total); \
p = sp->buffer; \
_Pragma("pop_macro(\"X\")") \
X_Fields \
; \
}
#include "create_allocator_helper.h"
CREATE_ALLOCATOR(A, X(x) X(y))
#include "create_allocator_helper.h"
CREATE_ALLOCATOR(B, X(w) X(y) X(z))
帮助程序头文件定义和推送一些由 CREATE_ALLOCATOR
宏使用的 X 宏定义:
#ifdef X
#undef X
#endif
#define X(A) ; sp->A = p; p = sp->A + n
#pragma push_macro("X")
#undef X
#define X(A) + sizeof(sp->A)
#pragma push_macro("X")
#undef X
关于c - 如何使用相同的函数初始化相似的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34867013/