是否可以在C中动态定义一个结构体 [英] Is it possible to dynamically define a struct in C

查看:147
本文介绍了是否可以在C中动态定义一个结构体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很确定这将是一个非常明显的问题,这就是为什么我没有找到很多信息。不过,我认为这是值得问的:)



基本上,使用结构体访问数据真的很快。如果数据以可以立即被处理为结构体的形式从网络中脱离出来,那么从性能的角度来看,这是非常好的。



然而,是否可能动态定义一个结构。客户端和服务器应用程序可以协商数据流的格式,然后将该定义用作结构体吗?



如果没有,是否有更好的方法? p>

感谢所有!

解决方案

不可能动态定义结构与编译时结构相同。



创建可以包含与struct相当的信息的动态结构是有可能但很困难的。访问数据不如编译时可用的那样方便。



除此之外,您无法访问成员 somestruct.not_seen_at_compile_time 使用 - > 如果编译时没有定义符号



对于网络通信,还有其他问题需要解决 - 特别是字节顺序。也就是说,电线上的数据可能包括多字节(2,4,8)整数,并且首先发送MSB或LSB,但如果一台机器是小端(IA-32,IA- 64,x86 / 64),另一个是大端(SPARC,PPC,几乎不是来自英特尔),那么数据将需要转换。浮点格式也是有问题的。有许多标准专门用于定义如何通过网络发送数据 - 这不是微不足道的。一些是具体的:IP,TCP,UDP;其他的是一般的,如ASN.1。



但是,不能做动态数据结构部分限制事情 - 您必须事先同意数据结构是什么,以及他们将如何解释。






你该怎么做?



gerty3000 询问:


创建可以包含与struct相当的信息的动态结构是有可能但很困难的。 - 你如何做?我想将动态定义的结构传递给其他C代码(假定相同的编译器和其他设置),而无需从编译器复制结构体内存布局例程。我不会在我的进程中访问这些结构体的字段(只是初始化一次),所以方便的语法不是一个问题。


您不能在没有以某种形式或形式复制内存布局的情况下执行此操作。它可能不一定完全一样,但如果是这样的话可能是最好的。以下是一些示例代码,大致显示如何进行。



dynstruct.c



结构操纵材料 - 用于描述结构和(简单)成员的结构。处理完整的数组(而不是字符串)将需要更多的工作,而且还有大量的make-work复制被管理用于其他类型。



它还包含一个测试代码的 main()程序。它调用 other_function(),这表明我在数据结构中定义的结构完全匹配结构。数据确实假设一个64位机器,其中 double 必须在8字节边界上对齐(因此在结构中有一个4字节的孔);您将不得不调整一个机器的数据,其中 double 可以在4字节的边界。

  #include< assert.h> 
#include< stdio.h>
#include< stdlib.h>
#include< string.h>

/ *这是将被动态模拟的类型* /
/ *
struct simulated
{
int number;
双重值;
char string [32];
};
* /

/ * SOF structure.h * /
typedef枚举类型{INT,DOUBLE,STRING}类型;

typedef struct Descriptor
{
size_t offset;
类型;
size_t type_size;
size_t array_dim;
char name [32];
}描述符;

typedef struct结构
{
size_t size;
char name [32];
描述符*细节;
}结构;

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描述符详细信息[] =
{
{0,INT,sizeof(int),1,number },
{8,DOUBLE,sizeof(double),1,value},
{16,STRING,sizeof(char),32,string},
};

static结构模拟= {48,模拟,细节};

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 ;
返回数据;
}

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(& simulation);

if(sp!= 0)
{
set_int_element(sp,& simulated.details [0],37);
set_double_element(sp,& simulator.details [1],3.14159);
set_string_element(sp,& simulator.details [2],绝对废话);
printf(Main(before):\\\
);
printf(Integer:%d\\\
,get_int_element(sp,& simulator.details [0]));
printf(Double:%f\\\
,get_double_element(sp,& simulator.details [1]));
printf(String:%s\\\
,get_string_element(sp,& simulator.details [2]));
other_function(sp);
printf(Main(after):\\\
);
printf(Integer:%d\\\
,get_int_element(sp,& simulator.details [0]));
printf(Double:%f\\\
,get_double_element(sp,& simulator.details [1]));
printf(String:%s\\\
,get_string_element(sp,& simulator.details [2]));

deallocate_structure(sp);
}
return 0;
}



other.c



此代码对 dynstruct.c 中的结构描述材料一无所知;它知道模拟代码模拟的 struct模拟。它打印通过的数据并修改它。

  #include< stdio.h> 
#include< string.h>

extern void other_function(void * p);

struct simulated
{
int number;
双重值;
char string [32];
};

void other_function(void * p)
{
struct simulated * s =(struct simulated *)p;

printf(其他功能:\\\
);
printf(Integer:%d\\\
,s-> number);
printf(Double:%f\\\
,s-> value);
printf(String:%s\\\
,s-> string);

s-> number * = 2;
s-> value / = 2;
strcpy(s-> string,Codswallop);
}



样本输出



 主(以前):
整数:37
双重:3.141590
字符串:绝对废话
其他功能:
整数: 37
双倍:3.141590
字符串:绝对废话
主(后):
整数:74
双倍:1.570795
字符串:Codswallop

显然,此代码没有准备就绪。这是充分证明可以做的事情。您必须处理的一个问题是正确地初始化结构描述符数据。你不能把太多的断言放在这种代码中。例如,我应该在中获得 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 ++编译器。 p>

I'm pretty sure this will end up being a really obvious question, and that's why I haven't found much information on it. Still, I thought it was worth asking :)

Basically, accessing data using a struct is really fast. If data comes off the network in a form where it can be immediately processed as a struct, this is pretty sweet from a performance point of view.

However, is it possible to define a struct dynamically. Could a client and server app negotiate the format of the datastream and then use that definition as a struct?

If not, is there a better way of doing it?

Thanks all!

解决方案

It isn't possible to dynamically define a struct that is identical to a compile-time struct.

It is possible, but difficult, to create dynamic structures that can contain the information equivalent to a struct. The access to the data is less convenient than what is available at compile-time.

All else apart, you cannot access a member somestruct.not_seen_at_compile_time using the . or -> notation if it was not defined at compile-time.

With network communications, there are other issues to address - notably 'endianness'. That is, the data on the wire will probably include multi-byte (2, 4, 8) integers, and either the MSB or the LSB will be sent first, but if one machine is little-endian (IA-32, IA-64, x86/64) and the other is big-endian (SPARC, PPC, almost anything not from Intel), then the data will need to be transformed. Floating point formats can also be problematic. There are numerous standards dedicated to defining how data will be sent across the network - it is not trivial. Some are specific: IP, TCP, UDP; others are general, such as ASN.1.

However, the 'cannot do dynamic data structures' part limits things - you have to agree beforehand on what the data structures are, and how they will be interpreted.


How do you do that?

gerty3000 asks:

It is possible, but difficult, to create dynamic structures that can contain the information equivalent to a struct. — How do you do that? I would like to pass dynamically-defined structs off to other C code (assume same compiler and other settings) without having to duplicate the struct memory layout routines from the compiler. I won't be accessing fields of these structs inside my process much (just initializing them once), so convenient syntax is not a concern.

You can't do it without duplicating the memory layout in some shape or form. It might not have to be exactly the same, but it is likely best if it is. Here's some sample code that shows roughly how it might be done.

dynstruct.c

This contains the basic structure manipulation material — structures to describe structures and (simple) members. Handling full arrays (as opposed to strings) would require more work, and there's a good deal of make-work replication to be managed for other types.

It also contains a main() program that tests the code. It makes a call to other_function(), which demonstrates that the structure I've defined in the data structures does match the structure exactly. The data does assume a 64-bit machine where double must be aligned on an 8-byte boundary (so there's a 4-byte hole in the structure); you will have to tweak the data for a machine where double can be on a 4-byte boundary.

#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

This code knows nothing about the structure description material in dynstruct.c; it knows about the struct simulated that the simulation code simulates. It prints the data it is passed and modifies it.

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

Sample output

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

Clearly, this code is not production ready. It is a sufficient demonstration of what can be done. One issue you'd have to deal with is initializing the Structure and Descriptor data correctly. You can't put too many assertions into that sort of code. For example, I should really have assert(d->size == sizeof(double); in get_double_element(). It would also be sensible to include assert(d->offset % sizeof(double) == 0); to ensure that the double element is properly aligned. Or you might have a validate_structure(const Structure *sp); function that did all these validation checks. You'd need a function void dump_structure(FILE *fp, const char *tag, const Structure *sp); to dump the defined structure to the given file preceded by the tag, to assist in debugging. Etc.

This code is pure C; it is not compilable by a C++ compiler as C++. There aren't enough casts to satisfy a C++ compiler.

这篇关于是否可以在C中动态定义一个结构体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆