我很确定这最终会成为一个非常明显的问题,这就是为什么我没有找到关于它的更多信息.不过,我认为值得问:)
基本上,使用结构访问数据非常快.如果数据以可以立即作为结构处理的形式从网络中传出,从性能的角度来看,这是非常好的.
但是,是否可以动态定义结构.客户端和服务器应用程序是否可以协商数据流的格式,然后将该定义用作结构?
如果没有,有没有更好的方法呢?
谢谢大家!
Jon*_*ler 20
无法动态定义与编译时结构相同的结构.
创建可以包含与结构等效的信息的动态结构是可能的,但也很困难.对数据的访问不如编译时可用的方便.
除此之外,如果未在编译时定义,则无法somestruct.not_seen_at_compile_time使用.或->表示法访问成员.
通过网络通信,还有其他问题需要解决 - 尤其是'endianness'.也就是说,线上的数据可能包括多字节(2,4,8)整数,MSB或LSB将首先发送,但如果一台机器是小端(IA-32,IA-) 64,x86/64)和另一个是big-endian(SPARC,PPC,几乎所有不是来自英特尔),那么数据将需要转换.浮点格式也可能存在问题.有许多标准致力于定义如何通过网络发送数据 - 这不是微不足道的.一些是特定的:IP,TCP,UDP; 其他是一般性的,例如ASN.1.
然而,'不能做动态数据结构'部分限制了事情 - 您必须事先就数据结构是什么以及如何解释它们达成一致.
创建可以包含与结构等效的信息的动态结构是可能的,但也很困难.- 你是怎样做的?我想将动态定义的结构传递给其他C代码(假设相同的编译器和其他设置),而不必从编译器复制结构内存布局例程.我不会在我的进程中访问这些结构的字段(只是初始化它们一次),所以方便的语法不是问题.
如果不以某种形状或形式复制内存布局,则无法执行此操作.它可能不一定完全相同,但如果是的话,它可能是最好的.这里有一些示例代码,大致显示了它是如何完成的.
这包含基本结构操作材料 - 描述结构和(简单)成员的结构.处理完整数组(而不是字符串)需要更多工作,并且需要为其他类型管理大量的make-work复制.
它还包含一个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;
}
Run Code Online (Sandbox Code Playgroud)
这段代码对结构描述材料一无所知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");
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
显然,这段代码还没有准备就绪.这足以证明可以做些什么.您必须处理的一个问题是正确初始化Structure和Descriptor数据.你不能在这种代码中加入过多的断言.例如,我要真有assert(d->size == sizeof(double);在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);将定义的结构转储到标记前面的给定文件,以帮助调试.等等.
这段代码是纯C; 它不能被C++编译器编译为C++.没有足够的强制转换来满足C++编译器.