C 中是否可以动态定义结构体

2024-05-23

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

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

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

如果没有,有更好的方法吗?

谢谢大家!


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

创建包含与结构等效的信息的动态结构是可能的,但很困难。访问数据不如编译时方便。

除此之外,您无法访问会员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++ 编译器的要求。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 中是否可以动态定义结构体 的相关文章

随机推荐

  • 码头工人。将动态主机 IP 添加到容器上的环境变量

    我有一个非常特殊的场景 包含一些 docker 容器的虚拟机 该容器之一需要知道主机 IP 问题是如果我在容器构建时传递主机 IP 或使用 e在 docker run 命令上 它在容器上保持 静态 始终相同 那一刻 该虚拟机可以位于笔记本电
  • LaTeX 报告章节样式

    如何更改 LaTeX 报告类中的章节样式 我发现了一些关于 makechapterstyle 但它似乎不适用于报告 或者至少不适用于my报告 我很确定一定有某种方法可以改变这一点 我知道 LaTeX 不太适合编程 但我不知道有什么更好的地方
  • 如何避免使用 python 处理空的标准输入?

    The sys stdin readline 返回之前等待 EOF 或新行 所以如果我有控制台输入 readline 等待用户输入 相反 我想打印帮助并在没有需要处理的情况下退出并显示错误 而不是等待用户输入 原因 我正在寻找一个Pytho
  • 将字符串解析为结构变量

    我试图将字符串解析为其中包含不同变量的结构向量 这是我到目前为止所拥有的 但似乎不起作用 struct client string PhoneNumber string FirstName string LastName string Ag
  • 使用 xtable 对乳胶输出的表进行排序

    我正在尝试生成一个排序表并导出到乳胶中 然而 xtable 似乎无法处理排序表 建议 a lt sample letters 500 replace T b lt table a c lt sort table a decreasing T
  • 计算引擎启动脚本无法以非 root 用户身份执行

    将我的问题归结为最简单的情况 我使用带有以下启动脚本的 Compute Engine bin bash sudo useradd m drupal su drupal cd home drupal touch test txt 我可以确认
  • 错误类型 3 - 活动类不存在

    我正在尝试运行 webRTC 应用程序 但返回以下错误 启动应用程序 com onlinevoicecallapp com onlinevoicecallapp MainActivity 设备外壳命令 am start n com onli
  • 缺少嵌入互操作类型属性

    在一个 C 项目中 我收到以下警告 警告 CS1762 创建了对嵌入式互操作程序集 Interop SomeLibrary dll 的引用 因为间接引用了程序集 ALibraryOfMine dll 创建的该程序集 考虑更改任一程序集的 嵌
  • 将SQL数据引入jquery availabletag

    我正在尝试制作自动完成文本框 但如何将 SQL 数据包含到 jquery 可用标记并循环它 我无法根据以下代码执行该功能 任何帮助 将不胜感激 谢谢 这是我的预期输出 预期结果演示 http jsfiddle net VvETA 71 jq
  • Reactive Spring 不支持 HttpServletRequest 作为 REST 端点中的参数?

    我创建了一个 RestController 如下所示 RestController public class GreetingController RequestMapping value greetings method RequestM
  • PostgreSQL WHERE 计数条件

    我在 PostgreSQL 中有以下查询 SELECT COUNT a log id AS overall count FROM Log as a License as b WHERE a license id 7 AND a licens
  • CryptoJS 使用密码加密 AES,但 PHP 解密需要密钥

    我在用CryptoJS https code google com p crypto js AES加密字符串 function doHash msg msg String msg var passphrase aggourakia var
  • 获取 .wav 文件长度或持续时间

    我正在寻找一种方法来找出 python 中音频文件 wav 的持续时间 到目前为止我已经了解了 pythonwave图书馆 mutagen pymedia pymad我无法获取 wav 文件的持续时间 Pymad给了我持续时间 但它不一致
  • MongoDB中批量FindAndModify的解决方案

    我的用例如下 我在 mongoDB 中有一组文档 我必须发送这些文档进行分析 文件格式如下 id ObjectId 517e769164702dacea7c40d8 日期 1359911127494 状态 可用 其他字段 我有一个阅读器进程
  • ASP.NET MVC 站点中的覆盖视图不起作用

    我的解决方案中有一个单独的项目 其中包含一些控制器和编译的视图 我将这些控制器用作 MVC 应用程序中其他控制器的基类 并使用 RazorGenerator 编译视图 可以说B是具有非抽象操作方法的基本控制器一些动作返回视图 MyView
  • 新 Rails 应用程序出现问题

    我刚刚创建了一个新的rails应用程序 在CL上 使用rails new 我使用的是4 2 6 但似乎在我对应用程序执行任何操作之前我遇到了错误 first config environments development rb 53 in
  • 在另一个文件中扩展类的正确方法是什么?

    这就是我在 foo php 中的内容 class Foo public foo NULL public foo2 NULL public function setFoo foo foo2 this gt foo foo this gt fo
  • iOS5 和 Facebook API

    我想将我的应用程序与 Facebook 集成并从 github 下载 Facebook ios sdk 但是 该 sdk 适用于 Xcode 4 0 代码库 我正在使用 Xcode 4 2 for iOS 5 beta 5 应用程序 是否有
  • 带 Markdown 的两栏布局

    我正在编写并排文本 我必须用两列布局来准备这个 例如 一列包含英文文本 其他列 右列包含前面 英文 文本的翻译 Markdown 不支持表格标记 但 Github Flavored Markdown 支持 我做了一些尝试 但不幸的是无法解决
  • C 中是否可以动态定义结构体

    我很确定这最终将成为一个非常明显的问题 这就是为什么我没有找到太多关于它的信息 不过 我认为还是值得问一下 基本上 使用结构访问数据非常快 如果数据以一种可以立即作为结构进行处理的形式从网络中出来 那么从性能的角度来看 这是非常好的 但是