是否可以在C中动态定义结构
我很确定这最终会成为一个非常明显的问题,这就是为什么我没有找到太多关于它的信息。尽管如此,我还是觉得值得一问:) 基本上,使用结构访问数据非常快。如果数据以一种可以立即作为结构进行处理的形式离开网络,那么从性能的角度来看,这是非常好的 但是,是否可以动态定义结构。客户端和服务器应用程序是否可以协商数据流的格式,然后将该定义用作结构 如果没有,还有更好的方法吗是否可以在C中动态定义结构,c,dynamic,struct,C,Dynamic,Struct,我很确定这最终会成为一个非常明显的问题,这就是为什么我没有找到太多关于它的信息。尽管如此,我还是觉得值得一问:) 基本上,使用结构访问数据非常快。如果数据以一种可以立即作为结构进行处理的形式离开网络,那么从性能的角度来看,这是非常好的 但是,是否可以动态定义结构。客户端和服务器应用程序是否可以协商数据流的格式,然后将该定义用作结构 如果没有,还有更好的方法吗 谢谢大家 不,不是C语言,所有数据类型都必须在编译时知道。这就是它“非常快”的原因。不可能动态定义与编译时结构相同的结构 创建包含与结构等
谢谢大家 不,不是C语言,所有数据类型都必须在编译时知道。这就是它“非常快”的原因。不可能动态定义与编译时结构相同的结构
创建包含与结构等效的信息的动态结构是可能的,但很困难。对数据的访问不如编译时可用的方便 除此之外,如果未在编译时定义成员
或箭头->
符号,则无法在编译时访问该成员somestruct.not\u seen\u
对于网络通信,还有其他问题需要解决——特别是“端性”。也就是说,线路上的数据可能包括多字节(2、4、8)整数,并且将首先发送MSB或LSB,但是如果一台机器是little-endian(IA-32、IA-64、x86/64),而另一台是big-endian(SPARC、PPC,几乎所有不是Intel提供的东西),则需要转换数据。浮点格式也可能有问题。有许多标准专门用于定义如何通过网络发送数据——这不是小事。有些是特定的: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;
}
样本输出
Main(之前):
整数:37
双人票:3.141590
字符串:绝对是胡说八道
其他职能:
整数:37
双人票:3.141590
字符串:绝对是胡说八道
主要(后):
整数:74
双人房:1.570795
字符串:Codswallop
显然,这段代码还没有准备好生产。这充分证明了我们可以做些什么。您必须处理的一个问题是正确初始化结构
和描述符
数据。你不能在那种代码中放太多断言。例如,我应该在get\u double\u element()
中使用assert(d->size==sizeof(double);
来确保double
元素正确对齐。或者可以使用validate\u结构(const structure*sp)来包含assert(d->offset%sizeof(double)==0);
;
完成所有这些验证检查的函数。您需要一个函数void dump_结构(FILE*fp,const char*tag,const structure*sp);
将定义的结构转储到标签前面的给定文件,以协助调试。等等
此代码为纯C;C++编译器不可编译为C++。没有足够的强制转换满足C++编译器。< /P> < >动态结构,答案是“否”< /P>
如果你知道C++中的数据是什么,你可以使用重载你不能定义一个源级别结构,但是你可以通过建立一个数据结构来存储你想要通信的每个字段的名称/标签和偏移量,然后按照正确的偏移量存储/读取数据。为便于移植,将其扩展到一个大小为
sizeof(type)倍数的边界。当然,除非您确定客户端和服务器将具有相同的数据表示形式(endianness和其他注意事项)如果真的需要直接访问的性能,我会编写适当的序列化和反序列化例程…另一种理论上的可能性是在运行时使用编译器库(如libtcc)编译一些代码
虽然在理论上非常吸引人(它听起来确实像是一个自我修改的应用程序——您的应用程序只需为结构生成C代码并将其插入模板中,然后要求libtcc编译它,然后调用模板中定义的一些函数即可使用该结构
#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");
}
#ifndef TYPE_MACHINE_H
#define TYPE_MACHINE_H
#ifdef __cplusplus
extern "C" {
#endif
#define B8 char
#define B8U unsigned char
#define B16 short
#define B16U unsigned short
#define B32 int
#define B32U unsigned int
#define B64 long long int
#define B64U unsigned long long int
#define BP32 float
#define BP64 double
#define BIT_ON(var,bit) ((var)=((var) | (bit)))
#define BIT_OFF(var,bit) ((var)=((var) & (~bit)))
#define BIT_IS_ON(var,bit) (var & bit)
#define PAIR(position,value) ((value)=((position) << (1)))
typedef struct Bit8Tag BIT;
typedef enum {
Off, On
} STATUS;
typedef enum {
B8_T, B8U_T, B16_T, B16U_T, B32_T, B64_T, B64U_T, B32U_T, BP32_T, BP64_T
} TYPE;
typedef struct ClassFieldTag ClassField;
typedef struct ClassTag Class;
typedef enum {
CLASS_SIZE, CLASS_INSERT, CLASS_SHOW
} CLASS_MODE;
#if (defined(WIN32) || defined(WINDOWS_XP))
#define is_win()(1)
#else
#define is_win()(0)
#define TYPE_CALL
#define TYPE_TYPE
#endif // WIN32
#include <math.h>
#include <string.h>
#include <assert.h>
#define area(a,b) ((a)*(b))
#define radian(x,y)(atan2(y,x))
#define angle(a)( (a * (180 / M_PI)) + 180)
#if defined WIN32
#define ARIAL_PATH "C:/Windows/Fonts/arial.ttf\0"
#else
#define ARIAL_PATH "home/media/TheGreat/\0"
#endif
struct ClassFieldTag {
TYPE type;
size_t mem, size, len;
B8 name[32];
struct ClassFieldTag * next, *preview;
};
extern ClassField * class_set_push();
extern ClassField * class_field_set(ClassField * set, TYPE type, B8 * name, size_t len, size_t mem);
extern STATUS class_set_next_back(ClassField ** set, ClassField * next);
extern STATUS class_set_next_front(ClassField ** set, ClassField * next);
extern STATUS class_insert_back(Class * set, TYPE type, B8 * name, size_t len);
extern STATUS class_insert_front(Class * set, TYPE type, B8 * name, size_t len);
struct ClassTag {
B8 name[32];
void * data;
B8 * String;
B16 Short;
B16U UShort;
B32 Int;
B32U UInt;
B64 Long;
B64 ULong;
BP32 Float;
BP64 Double;
ClassField * field;
};
Class * class_push(B8 name[32]);
extern STATUS class_zero(Class * set, B8 name[32]);
extern void class_data_push(Class * set);
extern void class_data_pop(Class * set);
extern void * class_set_to(Class * set, ClassField * field);
extern void class_int_set(Class * set, ClassField * field, B32 value);
extern B32 class_int_get(Class * set, ClassField * field);
extern void class_double_set(Class * set, ClassField * field, BP64 value);
extern BP64 class_double_get(Class * set, ClassField * field);
extern void class_string_set(Class * set, ClassField * field, B8 * value);
extern B8 * class_string_get(Class * set, ClassField * field);
extern void class_mode(Class * set, ClassField * field, CLASS_MODE mode);
extern void class_field_pop(Class * set);
extern void class_pop(Class * set);
extern STATUS class_ex(Class * mine);
struct Bit8Tag {
unsigned b16 : 16;
};
extern void bit_on(BIT * value, int bit);
extern void bit_off(BIT * value, int bit);
extern STATUS bit_is_on(BIT value, int bit);
extern B32U strsub(B8 * data, B8 * key);
#ifdef __cplusplus
}
#endif
#endif // TYPE_MACHINE_H
#include <Place/include/type-machine.h>
#include <malloc.h>
#include <stdio.h>
Class * class_push(B8 name[32]) {
Class * set = (Class *) malloc(sizeof (Class));
if(class_zero(set,name)){
return(set);
}
return(NULL);
}
void class_data_push(Class * set) {
B32 class_size = sizeof (Class), class_field_size = sizeof (ClassField);
if (set) {
if (class_size < sizeof (set))class_size = sizeof (set);
if (class_field_size < sizeof (set->field))class_field_size = sizeof (set->field);
}
set->data = malloc(class_size + class_field_size + 1);
}
void class_data_pop(Class * set) {
if (set && set->data) {
free(set->data);
}
}
void * class_set_to(Class * set, ClassField * field) {
if (set && set->data && field) {
void * data = (char *) set->data + field->mem;
return data;
}
return (NULL);
}
void class_int_set(Class * set, ClassField * field, B32 value) {
if (set) {
assert(field->type == B32_T);
B32 * update = class_set_to(set, field);
*update = value;
}
}
B32 class_int_get(Class * set, ClassField * field) {
if (set) {
assert(field->type == B32_T);
B32 * data = class_set_to(set, field);
return (*data);
}
return (0);
}
void class_double_set(Class * set, ClassField * field, BP64 value) {
if (set) {
assert(field->type == BP64_T);
BP64 * update = class_set_to(set, field);
*update = value;
}
}
BP64 class_double_get(Class * set, ClassField * field) {
if (set) {
assert(field->type == BP64_T);
BP64 * data = class_set_to(set, field);
return (*data);
}
return (0);
}
void class_string_set(Class * set, ClassField * field, B8 * value) {
if (set && field && field->len > 1 && value) {
assert(field->type == B8_T);
size_t len = strlen(value);
if (len < 2) {
len = 2;
}
if (len > field->len)len = field->len - 1;
B8 * buffer = class_set_to(set, field);
if (buffer) {
memmove(buffer, value, len);
buffer[len] = '\0';
}
}
}
B8 * class_string_get(Class * set, ClassField * field) {
if (set && field) {
assert(field->type == B8_T);
B8 * data = class_set_to(set, field);
return (data);
}
return (NULL);
}
STATUS class_zero(Class * set, B8 * name) {
if (set) {
set->String = NULL;
set->Short = 0;
set->UShort = 0;
set->Int = 0;
set->UInt = 0;
set->Long = 0;
set->ULong = 0;
set->Float = 0;
set->Double = 0;
set->data = NULL;
memset(set->name, 0, sizeof (set->name));
if (name)memmove(set->name, name, strlen(name));
set->field = NULL;
return (On);
}
return (Off);
}
ClassField * class_set_push() {
return (malloc(sizeof (ClassField)));
}
void class_field_pop(Class * set) {
if (set) {
ClassField * field = set->field;
while (field) {
ClassField * next = field->next;
if (field) {
free(field);
field = NULL;
}
field = next;
}
}
}
void class_pop(Class * set) {
if (set) {
class_data_pop(set);
class_field_pop(set);
free(set);
set = NULL;
}
}
ClassField * class_field_set(ClassField * field, TYPE type, B8 * name, size_t len, size_t mem) {
if (field) {
size_t lenght = (name) ? strlen(name) : 0;
if (lenght > 32) {
lenght = 31;
}
memcpy(field->name, name, lenght);
field->name[lenght] = 0;
field->type = type;
field->mem = mem;
field->len = len;
class_mode(NULL, field, CLASS_SIZE);
field->next = NULL;
field->preview = NULL;
return (field);
}
return (NULL);
}
STATUS class_set_next_back(ClassField ** field, ClassField * next) {
if (next == NULL)return (Off);
next->next = *field;
if (*field != NULL) {
(*field)->preview = next;
}
*field = next;
return (On);
}
STATUS class_set_next_front(ClassField ** field, ClassField * next) {
if (next == NULL)return (Off);
if (*field != NULL) {
ClassField * update = *field, *preview = NULL;
while (update->next != NULL) {
preview = update;
update = update->next;
}
update->preview = preview;
update->next = next;
return (On);
}
*field = next;
return (On);
}
STATUS class_insert_back(Class * set, TYPE type, B8 * name, size_t len) {
if (class_set_next_back(&set->field, class_field_set(class_set_push(), type, name, len, 0))) {
ClassField * preview = set->field;
if (preview->next) {
preview->mem = preview->next->mem + preview->next->size;
}
return (On);
}
return (Off);
}
STATUS class_insert_front(Class * set, TYPE type, B8 * name, size_t len) {
ClassField * next = class_field_set(class_set_push(), type, name, len, 0);
if (class_set_next_front(&set->field, next)) {
ClassField * preview = set->field;
while (preview) {
if (preview->next) {
if (preview->next == next) {
next->mem = preview->mem + preview->size;
}
}
preview = preview->next;
}
return (On);
}
return (Off);
}
void class_mode(Class * set, ClassField * field, CLASS_MODE mode) {
if (field) {
switch (field->type) {
case B8_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: %s\n", field->name, class_string_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = field->len * sizeof (B8);
}
break;
case CLASS_INSERT:
{
class_string_set(set, field, set->String);
}
break;
}
}
break;
case B8U_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: %s\n", field->name, class_string_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = field->len * sizeof (B8U);
}
break;
case CLASS_INSERT:
{
class_string_set(set, field, set->String);
}
break;
}
}
break;
case B16_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: [%i]\n", field->name, class_int_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (B16);
}
break;
case CLASS_INSERT:
{
class_int_set(set, field, set->Int);
}
break;
}
}
break;
case B16U_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: [%i]\n", field->name, class_int_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (B16U);
}
break;
case CLASS_INSERT:
{
class_int_set(set, field, set->Int);
}
break;
}
}
break;
case B32_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: %i\n", field->name, class_int_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (B32);
}
break;
case CLASS_INSERT:
{
class_int_set(set, field, set->Int);
}
break;
}
}
break;
case B32U_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: [%i]\n", field->name, class_int_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (B32U);
}
break;
case CLASS_INSERT:
{
class_int_set(set, field, set->Int);
}
break;
}
}
break;
case B64_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: [%i]\n", field->name, class_int_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (B64);
}
break;
case CLASS_INSERT:
{
class_int_set(set, field, set->Int);
}
break;
}
}
break;
case B64U_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: [%i]\n", field->name, class_int_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (B64U);
}
break;
case CLASS_INSERT:
{
class_int_set(set, field, set->Int);
}
break;
}
}
break;
case BP32_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: [%lf]\n", field->name, class_double_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (BP32);
}
break;
case CLASS_INSERT:
{
class_double_set(set, field, set->Double);
}
break;
}
}
break;
case BP64_T:
{
switch (mode) {
case CLASS_SHOW:
{
printf("%s: [%lf]\n", field->name, class_double_get(set, field));
}
break;
case CLASS_SIZE:
{
field->size = sizeof (BP64);
}
break;
case CLASS_INSERT:
{
class_double_set(set, field, set->Double);
}
break;
}
}
break;
}
}
}
void bit_on(BIT * value, int bit) {
BIT_ON(value->b16, bit);
}
void bit_off(BIT * value, int bit) {
BIT_OFF(value->b16, bit);
}
STATUS bit_is_on(BIT value, int bit) {
if (value.b16 & bit)return (On);
return (Off);
}
B32U strsub(B8 * data, B8 * key) {
if (data && key) {
B8 *d = data;
B32U len = strlen(key), p = 0;
if (len > strlen(d))return (0);
while (*d != '\0') {
if (*(d + len) != '\0') {
B32U x = 0;
while (x <= len) {
if (key[x] == *d) {
*d++;
p++;
} else break;
x++;
}
if (x == len)return (p);
} else if (len == 1) {
if (*d == key[0])return (p);
}
p++;
*d++;
}
}
return (0);
}
#include "network.h"
#include <conio.h>
STATUS class_ex(Class * set) {
class_data_push(set);
if (set->data) {
ClassField * field = set->field;
while (field) {
if (!strcmp(field->name, "peso")) {
set->Double = 65.5;
}
if (!strcmp(field->name, "idade")) {
set->Int = 29;
}
if (!strcmp(field->name, "nome")) {
set->String = "Lisias de Castro Martins";
}
if (!strcmp(field->name, "endereco")) {
set->String = "Rua Mae D'Agua";
}
class_mode(set, field, CLASS_INSERT);
class_mode(set, field, CLASS_SHOW);
field = field->next;
}
return (On);
}
return (Off);
}
int main(int argc, char** argv) {
STATUS client_start = On;
if (client_start) {
Class * client = class_push("Client");;
class_insert_back(client, BP64_T, "peso", 1);
class_insert_back(client, B8_T, "endereco", 32);
class_insert_back(client, B32_T, "idade", 1);
class_insert_back(client, B8_T, "nome", 64);
printf("Classe[%s]\n\n", client->name);
if (class_ex(client)) {
}
class_pop(client);
getch();
}
return (EXIT_SUCCESS);
}