23

这是在使用 C struct hack 时如何使用分配的“额外”内存吗?

问题:

我在下面有一个 C struct hack 实现。我的问题是如何使用我分配给黑客的“额外”内存。有人可以给我一个使用额外内存的例子吗?

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

int main()
{

    struct mystruct {

        int len;
        char chararray[1];

    };

    struct mystruct *ptr = malloc(sizeof(struct mystruct) + 10 - 1);
    ptr->len=10;


    ptr->chararray[0] = 'a';
    ptr->chararray[1] = 'b';
    ptr->chararray[2] = 'c';
    ptr->chararray[3] = 'd';
    ptr->chararray[4] = 'e';
    ptr->chararray[5] = 'f';
    ptr->chararray[6] = 'g';
    ptr->chararray[7] = 'h';
    ptr->chararray[8] = 'i';
    ptr->chararray[9] = 'j';


}
4

4 回答 4

18

是的,那是(并且曾经是)C创建和处理可变大小的struct.

这个例子有点冗长。大多数程序员会更巧妙地处理它:

struct mystruct {
        int len;
        char chararray[1];  // some compilers would allow [0] here
    };
    char *msg = "abcdefghi";
    int n = strlen (msg);

    struct mystruct *ptr = malloc(sizeof(struct mystruct) + n + 1);

    ptr->len = n;
    strcpy (ptr->chararray, msg);
}
于 2013-05-14T22:02:19.520 回答
5

自从我阅读这篇文章 ( http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx ) 以来,我就喜欢像这样使用 struct hack:

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

  int main()
  {

      struct mystruct {

          int len;
          char chararray[1];
      };

      int number_of_elements = 10;

      struct mystruct *ptr = malloc(offsetof(struct mystruct, chararray[number_of_elements]));
      ptr->len = number_of_elements;

      for (i = 0; i < number_of_elements; ++i) {
        ptr->chararray[i] = 'a' + i;
      }

  }

我发现不必记住是否需要减去(或添加或其他)1 很好。这还具有在数组定义中使用的情况下工作的好处0,并非所有编译器都支持,但有些编译器支持。如果分配是基于offsetof()你不需要担心可能的细节使你的数学错误。

它也可以不加改变地工作,因为 struct 是 C99 灵活的数组成员。

于 2013-05-14T22:09:22.997 回答
1

由于可能的对齐问题,我建议不要这样做,而是考虑这个:

struct my_struct
{
    char *arr_space;
    unsigned int len;
}

struct my_struct *ptr = malloc(sizeof(struct my_struct) + 10);
ptr->arr_space = ptr + 1;
ptr->len = 10;

这将为您提供位置和安全性:) 并避免奇怪的对齐问题。

通过对齐问题,我的意思是访问未对齐的内存可能会出现访问延迟。

在原始示例中,如果您添加字节或非字对齐成员(字节、字符、短),则编译器可能会扩展结构的大小,但就您的指针而言,您是在结束后直接读取内存结构(非对齐)。这意味着,如果您有一个对齐类型的数组,例如int每次访问都会对 CPU 的性能造成影响,因为读取未对齐的内存会受到影响。

struct
{
    byte_size data;
    char *var_len;
    some_align added by compiler;
}

在原始情况下,您将从some_align只是填充的区域读取,但在我的情况下,您将在之后从对齐的额外内存中读取(这会浪费一些空间,但通常没关系)。

这样做的另一个好处是,可以通过struct在一个分配中为 a 的可变长度成员分配所有空间而不是单独分配它们来从分配中获得更多的局部性(避免多次分配调用开销并为您提供一些缓存局部性而不是弹回所有超过记忆)。

于 2013-05-14T22:02:10.220 回答
1

这是“正确的”,但您需要有充分的理由通过更合理的解决方案来做到这一点。更常见的是,您可能会使用这种技术来“覆盖”一些现有的数组,以对其施加某种标题结构。

请注意,GCC 通过扩展允许零长度数组成员正是为了这个目的,而 ISO C99 通过允许带有空括号的成员(仅作为最后一个成员)来“合法化”这种做法。

请注意,存在一些语义问题 - 结构的大小当然不会考虑最终成员的“灵活”大小,并且“按值”传递结构只会传递标题和第一个元素(或使用 GCC 不传递任何元素扩展名或 C99 灵活数组成员)。同样直接结构赋值不会复制所有数据。

于 2013-05-14T22:11:49.183 回答