不可能动态定义与编译时结构相同的结构。
创建包含与结构等效的信息的动态结构是可能的,但很困难。访问数据不如编译时方便。
除此之外,您无法访问会员somestruct.not_seen_at_compile_time
使用点.
或箭头->
如果未在编译时定义,则表示法。
对于网络通信,还有其他问题需要解决 - 特别是“字节顺序”。也就是说,线路上的数据可能包括多字节(2、4、8)整数,并且 MSB 或 LSB 将首先发送,但如果一台机器是小端字节序(IA-32、IA- 64、x86/64),另一个是大端(SPARC、PPC,几乎任何不是来自英特尔的),那么数据将需要转换。浮点格式也可能有问题。有许多标准专门用于定义数据如何通过网络发送 - 这并不简单。有些是特定的:IP、TCP、UDP;其他的是通用的,例如 ASN.1。
然而,“不能做动态数据结构”部分限制了一些事情——你必须事先就数据结构是什么以及如何解释它们达成一致。
你是怎样做的?
格蒂3000 https://stackoverflow.com/users/823872/gerty3000 asks:
创建包含与结构等效的信息的动态结构是可能的,但很困难。- 你是怎样做的?我想将动态定义的结构传递给其他 C 代码(假设相同的编译器和其他设置),而不必从编译器复制结构内存布局例程。我不会在进程中过多访问这些结构的字段(只需初始化一次),因此方便的语法不是问题。
如果不以某种形状或形式复制内存布局,就无法做到这一点。它可能不必完全相同,但如果完全相同可能是最好的。下面是一些示例代码,大致展示了如何完成它。
dynstruct.c
这包含基本的结构操作材料 - 描述结构和(简单)成员的结构。处理完整数组(相对于字符串)需要更多工作,并且需要为其他类型管理大量的工作复制。
它还包含一个main()
测试代码的程序。它打电话给other_function()
,这表明我在数据结构中定义的结构确实与结构完全匹配。数据确实假定是 64 位机器,其中double
必须在 8 字节边界上对齐(因此结构中存在 4 字节空洞);你将不得不调整机器的数据double
可以在 4 字节边界上。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* This is the type that will be simulated dynamically */
/*
struct simulated
{
int number;
double value;
char string[32];
};
*/
/* SOF structure.h */
typedef enum Type { INT, DOUBLE, STRING } Type;
typedef struct Descriptor
{
size_t offset;
Type type;
size_t type_size;
size_t array_dim;
char name[32];
} Descriptor;
typedef struct Structure
{
size_t size;
char name[32];
Descriptor *details;
} Structure;
extern void *allocate_structure(const Structure *structure);
extern void deallocate_structure(void *structure);
extern void *pointer_to_element(void *p, const Descriptor *d);
extern int get_int_element(void *p, const Descriptor *d);
extern void set_int_element(void *p, const Descriptor *d, int newval);
extern double get_double_element(void *p, const Descriptor *d);
extern void set_double_element(void *p, const Descriptor *d, double newval);
extern char *get_string_element(void *p, const Descriptor *d);
extern void set_string_element(void *p, const Descriptor *d, char *newval);
/* EOF structure.h */
static Descriptor details[] =
{
{ 0, INT, sizeof(int), 1, "number" },
{ 8, DOUBLE, sizeof(double), 1, "value" },
{ 16, STRING, sizeof(char), 32, "string" },
};
static Structure simulated = { 48, "simulated", details };
void *allocate_structure(const Structure *structure)
{
void *p = calloc(1, structure->size);
return p;
}
void deallocate_structure(void *structure)
{
free(structure);
}
void *pointer_to_element(void *p, const Descriptor *d)
{
void *data = (char *)p + d->offset;
return data;
}
int get_int_element(void *p, const Descriptor *d)
{
assert(d->type == INT);
int *v = pointer_to_element(p, d);
return *v;
}
void set_int_element(void *p, const Descriptor *d, int newval)
{
assert(d->type == INT);
int *v = pointer_to_element(p, d);
*v = newval;
}
double get_double_element(void *p, const Descriptor *d)
{
assert(d->type == DOUBLE);
double *v = pointer_to_element(p, d);
return *v;
}
void set_double_element(void *p, const Descriptor *d, double newval)
{
assert(d->type == DOUBLE);
double *v = pointer_to_element(p, d);
*v = newval;
}
char *get_string_element(void *p, const Descriptor *d)
{
assert(d->type == STRING);
char *v = pointer_to_element(p, d);
return v;
}
void set_string_element(void *p, const Descriptor *d, char *newval)
{
assert(d->type == STRING);
assert(d->array_dim > 1);
size_t len = strlen(newval);
if (len > d->array_dim)
len = d->array_dim - 1;
char *v = pointer_to_element(p, d);
memmove(v, newval, len);
v[len] = '\0';
}
extern void other_function(void *p);
int main(void)
{
void *sp = allocate_structure(&simulated);
if (sp != 0)
{
set_int_element(sp, &simulated.details[0], 37);
set_double_element(sp, &simulated.details[1], 3.14159);
set_string_element(sp, &simulated.details[2], "Absolute nonsense");
printf("Main (before):\n");
printf("Integer: %d\n", get_int_element(sp, &simulated.details[0]));
printf("Double: %f\n", get_double_element(sp, &simulated.details[1]));
printf("String: %s\n", get_string_element(sp, &simulated.details[2]));
other_function(sp);
printf("Main (after):\n");
printf("Integer: %d\n", get_int_element(sp, &simulated.details[0]));
printf("Double: %f\n", get_double_element(sp, &simulated.details[1]));
printf("String: %s\n", get_string_element(sp, &simulated.details[2]));
deallocate_structure(sp);
}
return 0;
}
other.c
这段代码对结构描述材料一无所知dynstruct.c
;它知道关于struct simulated
模拟代码模拟的。它打印传递的数据并修改它。
#include <stdio.h>
#include <string.h>
extern void other_function(void *p);
struct simulated
{
int number;
double value;
char string[32];
};
void other_function(void *p)
{
struct simulated *s = (struct simulated *)p;
printf("Other function:\n");
printf("Integer: %d\n", s->number);
printf("Double: %f\n", s->value);
printf("String: %s\n", s->string);
s->number *= 2;
s->value /= 2;
strcpy(s->string, "Codswallop");
}
样本输出
Main (before):
Integer: 37
Double: 3.141590
String: Absolute nonsense
Other function:
Integer: 37
Double: 3.141590
String: Absolute nonsense
Main (after):
Integer: 74
Double: 1.570795
String: Codswallop
显然,此代码尚未准备好用于生产。这足以证明可以做什么。您必须处理的一个问题是初始化Structure
and Descriptor
数据正确。您不能在此类代码中放入太多断言。例如,我真的应该有assert(d->size == sizeof(double);
in get_double_element()
。包括在内也是明智的assert(d->offset % sizeof(double) == 0);
以确保double
元素已正确对齐。或者你可能有一个validate_structure(const Structure *sp);
完成所有这些验证检查的函数。你需要一个函数void dump_structure(FILE *fp, const char *tag, const Structure *sp);
将定义的结构转储到给定文件(前面带有标记),以帮助调试。 ETC。
这段代码是纯C的;它不能被 C++ 编译器编译为 C++。没有足够的强制转换来满足 C++ 编译器的要求。