C语言 是否可以在C中动态定义结构

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6187908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:49:03  来源:igfitidea点击:

Is it possible to dynamically define a struct in C

cdynamicstruct

提问by PeterM

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!

谢谢大家!

采纳答案by Jonathan Leffler

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_timeusing the dot .or arrow ->notation if it was not defined at compile-time.

除此之外,如果成员未在编译时定义,则无法somestruct.not_seen_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.

对于网络通信,还有其他问题需要解决——尤其是“字节序”。也就是说,线路上的数据可能包括多字节 (2, 4, 8) 整数,并且将首先发送 MSB 或 LSB,但如果一台机器是小端 (IA-32, IA- 64、x86/64),另一个是 big-endian(SPARC、PPC,几乎所有不是来自 Intel 的东西),那么数据将需要进行转换。浮点格式也可能有问题。有许多标准专门用于定义如何通过网络发送数据——这并非微不足道。有些是特定的:IP、TCP、UDP;其他是通用的,例如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?

你是怎样做的?

gerty3000asks:

gerty3000问:

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.

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

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

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 doublemust 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 doublecan be on a 4-byte boundary.

它还包含一个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] = '
#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");
}
'; } 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

其他.c

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

这段代码对中的结构描述材料一无所知dynstruct.c;它知道struct simulated模拟代码模拟的内容。它打印它传递的数据并修改它。

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

Sample output

样本输出

#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
#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] = '
#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);
}
'; } } } 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 != '##代码##') { if (*(d + len) != '##代码##') { 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); }
" #else #define ARIAL_PATH "home/media/TheGreat/##代码##" #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

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 Structureand Descriptordata 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 doubleelement 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.

显然,此代码不是生产就绪的。它充分证明了可以做什么。您必须处理的一个问题是正确初始化StructureDescriptor数据。你不能在那种代码中加入太多的断言。例如,我真的应该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);将定义的结构转储到标记前面的给定文件中,以帮助调试。等等。

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 的;它不能被 C++ 编译器编译为 C++。没有足够的强制转换来满足 C++ 编译器的要求。

回答by Jonathan Leffler

No, it isn't in C all data types must be known at compile time. That's what makes it "real fast".

不,它不是在 C 中所有数据类型都必须在编译时知道。这就是使它“真正快速”的原因。

回答by fourmiant

Another theoretical possibility would be to compile some code at run-time using a compiler library such as libtcc.

另一种理论上的可能性是在运行时使用编译器库(如 libtcc)编译一些代码。

While very appealing in theory (it does sound like a self-modifying application – your application would only have to generate C code for your struct and insert it in a template, then ask libtcc to compile it and then call some functions defined in your template to use that struct), this solution will probably not work great in practice. Why?? Well, as of 2016, libtcc (and the whole tcc project) is not very actively developed and there are issues with architectures such as x86_64.

虽然理论上非常吸引人(听起来确实像一个自我修改的应用程序——你的应用程序只需要为你的结构生成 C 代码并将其插入模板中,然后让 libtcc 编译它,然后调用模板中定义的一些函数使用该结构),此解决方案在实践中可能不会很好地工作。为什么??好吧,截至 2016 年,libtcc(以及整个 tcc 项目)的开发并不十分活跃,并且 x86_64 等架构存在问题。

回答by fourmiant

For dynamic structure, the answer is no.

对于动态结构,答案是否定的。

If you know what data comes in, in C++, you can use the overloaded << in operator to read the data from the stream..

如果您知道输入了什么数据,在 C++ 中,您可以使用重载的 << in 运算符从流中读取数据。

In C, you could convert the stream to a string assuming that you know the length of the data comes in and using the function like sscanf, you could read the data.

在 C 中,您可以将流转换为字符串,假设您知道传入的数据的长度,并使用 sscanf 之类的函数,您可以读取数据。

回答by R.. GitHub STOP HELPING ICE

You can't define a source-level struct, but you could do the same thing by setting up a data structure to store a name/tag and offset for each field of the data you want to communicate, and then store/read data at the right offsets according to that. Be sure you align all types to a boundary that's a multiple of sizeof(type)for portability. Of course, unless you're sure the client and server will have the same data representations (endianness and other considerations) and really need the performance of direct access, I would write proper serialize and deserialize routines instead...

您不能定义源级结构,但您可以通过设置数据结构来存储您要通信的数据的每个字段的名称/标签和偏移量,然后在以下位置存储/读取数据来做同样的事情正确的偏移量。确保将所有类型与边界对齐,该边界是sizeof(type)可移植性的倍数。当然,除非您确定客户端和服务器将具有相同的数据表示(字节序和其他考虑因素)并且确实需要直接访问的性能,否则我会编写适当的序列化和反序列化例程......

回答by Lísias de Castro

Based on gerty3000's answer I made a library. I've abstracted something from the final user. It was hard buf finaly worked. If is there any improvement to do I am open for sugestions. Here it goes the code.

根据 gerty3000 的回答,我创建了一个库。我从最终用户那里抽象了一些东西。这很难 buf 终于奏效了。如果有任何改进要做,我愿意接受建议。这是代码。

type-machine.h // define types and function prototipes

type-machine.h // 定义类型和函数原型

##代码##

type-machine.c // declares those functions

type-machine.c // 声明这些函数

##代码##

main.c // testing....

main.c // 测试....

##代码##

I still have to implement the short double and some other functions, but it is working.

我仍然需要实现 short double 和其他一些功能,但它正在工作。