【问题标题】:Getting Size of Struct That Contains Dynamically Allocated Memory获取包含动态分配内存的结构的大小
【发布时间】:2013-05-31 20:36:17
【问题描述】:

我想为一个缓冲区分配内存,该缓冲区将来会通过 memcpy 包含一个结构,该结构包含一个先前已动态分配内存的指针。

也就是说,我有一个结构体

struct test_struct {
    int   num;
    char  *values;
};

其中test_struct.values 包含num 长度为LENGTH 的字符串数量。我知道我无法获得已分配指针的内存大小,所以我只是通过num 跟踪它。获取此结构大小的最简单/最干净的方法是什么?

我能想出的唯一解决方案是

buf = malloc(sizeof(test_struct) + (num * LENGTH));

但我对这种低级内存管理的东西不熟悉,所以可能会有更好的东西。

【问题讨论】:

  • 该结构的大小是恒定的
  • 结构的大小永远不会改变,它只是sizeof(test_struct)。如果您想知道分配的总内存,那么是的,您还需要num * sizeof(*values)
  • @Taylor 正确。但是,必须为包含它的缓冲区分配足够的内存来保存values。这就是为什么我用num*LENGTH 计算values 的大小,然后加上struct 本身的大小。
  • @justynnuff:那么,我不确定你的问题是什么?
  • @OliCharlesworth 我想我这个问题的措辞很糟糕。我应该添加我有一个缓冲区char *buf; 和一个结构struct test_struct t_struct;。为 buf 计算 malloc 的内存大小以便执行 memcpy(&buf, &t_struct, ???); 的最佳/最干净的方法是什么

标签: c memory-management


【解决方案1】:

如果您想 memcpy 两个结构,那么它们中的内存必须是连续的。但是您必须事先确定num

struct test_struct {
    int num;
    char ** values;
} * TestStruct;

int _num = 0;

// find _num

TestStruct = malloc (sizeof (struct test_struct) + (sizeof(char*) * _num) + (LENGTH * _num));

TestStruct->num = _num;
TestStruct->values = &TestStruct + sizeof (struct test_struct);

for (int i = 0; i < _num; i++){
    TestStruct->values[i] = &TestStruct + sizeof (struct test_struct) + (i * LENGTH);
}

我将 char * 更改为 char ** 的原因是因为使用 char * 在第一次之后访问字符串变得更加困难(我假设它们是空终止的)。此外,在调用 memcpy 之后,您必须更新新结构中的所有字符串指针。

要 memcpy 你可以这样做:

memcpy (buf, TestStruct->values[0], LENGTH * TestStruct->num);

但是在 buf 中,您只会看到第一个字符串(除非您的字符串不是以空值结尾的)。您必须在每个以空字符结尾的字符后递增指针,直到使用 num 知道您已经到达缓冲区的末尾。


现在我了解了您请求的更多上下文,请考虑以下内容。

如果您使用的是 UDP 数据包,您应该在一个数据包中发送数据,以便它以您期望的顺序到达。当发送多个数据包时,它可能会乱序到达。 因此,您需要确保数据的大小为 此外,您需要确保所有数据都是连续的记忆。我将假设您的数据已经在您在此示例中提供的结构中:

// this function puts the struct in contiguous memory

int PrepareBuffer (struct test_struct TestStruct, char ** buffer){

    char * cast = (char *) &TestStruct->num;

    * buffer = malloc ((TestStruct->num * LENGTH) + sizeof (int));

    for (int i = 0; i < sizeof (int); i++) *buffer[i] = cast[i];

    for (int i = 0; i < (TestStruct->num * LENGTH); i++) *buffer[i + sizeof (int)] = TestStruct->values[i];
    return 0;
}

您必须在接收端实现另一个函数,将缓冲区映射到struct test_struct。另外,为了清楚起见,我省略了错误检查。您应该在分配内存之前检查数据包的大小(它必须是。您还应该检查以确保 malloc 返回非空指针。

【讨论】:

  • 一个指针在 64 位机器上是 8 个字节,而 int 可能是 4。这只是一个猜测,可能准确也可能不准确
  • 是的,这也取决于编译器在做什么。即使在 64 位计算机上,如果在编译时请求,可能仍然有 32 位指针。
  • 使用 sizeof 总比猜测大小和对齐要好。在 64 位机器上,由于对齐,结构可能是 16 个字节而不是 12 个字节。
  • @TaylorFlores 顺便说一下,据我了解,UDP 数据包必须小于 512 字节才能避免碎片。但是,UDP 数据包的长度可以达到 2^16 - 1 (65535) 个字节,由标头长度字段中的位数定义。分片的数据包会在网络层重新组装,所以听起来好像缺少一个分片,整个数据包都会被丢弃。
  • 哦,不知道!我想你可以忽略那部分
【解决方案2】:

您应该只需要分配 4 个字节(用于 32 位 linux 上的整数)和 4 个字节用于 char *(在 32 位中。64 为 8)。

您真正要问的是,我如何知道需要为 char *value 指向的区域分配多少内存。你在你正在做的事情中弄清楚这一点。然后将 value 设置为 buf 的位置。如果你有多个字符串,有一条评论让我大吃一惊,这是正确的方法,你不想在那个区域把它们全部塞在一起,而必须自己弄清楚哪个是哪个。

【讨论】:

    【解决方案3】:

    我假设您要为结构和值指向的缓冲区分配内存。如果是这样,这是正确的。要指向额外的空间,请执行 buf-&gt;values = buf + 1;(假设您将 buf 声明为 struct test_struct buf;

    【讨论】:

    • 这个答案来自不久前,但只是为了澄清buf-&gt;values = buf + 1 并不指向额外的空间,它指向结构内buf-&gt;num 的偏移字节,它将溢出到@987654325 @。我想你的意思是buf-&gt;values = &amp;buf-&gt;values + sizeof (char*);
    • 我没有。在 C 中,将 1 加到指向 struct x 的指针会添加 sizeof (struct x),而不是 1。如果将 1 加到 char 指针,则确实会加 1。将 1 加到 32 位整数指针实际上会加4!
    • 啊,我在C++中遇到过,但我不知道它是从C开始的。
    猜你喜欢
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-06
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    相关资源
    最近更新 更多