C struct hack at work

时间:2013-05-14 21:59:31

标签: c

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

问题:

我在下面有一个C struct hack实现。我的问题是如何使用我分配给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 个答案:

答案 0 :(得分:15)

是的,这是({是})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);
}

答案 1 :(得分: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灵活的数组成员。

答案 2 :(得分: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;

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

通过对齐问题,我的意思是访问未对齐内存的访问延迟。

在原始示例中,如果添加一个字节或非字对齐的成员(byte,char,short),那么编译器可能会扩展结构的大小,但就指针而言,您正在读取内存后的内存。结构的结尾(未对齐)。这意味着如果您有一个对齐类型的数组,例如int,那么每次访问都会使您在读取未对齐内存时触及命中的CPU上遇到性能损失。

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

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

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

答案 3 :(得分:1)

这是'正确的',但你需要一个很好的理由来做一个更合理的解决方案。更常见的是,您可能会使用此技术“覆盖”某些现有数组,以对其施加某种标头结构。

请注意,GCC的扩展允许zero length array member用于此目的,而ISO C99通过允许具有空括号的成员(仅作为最后一个成员)使该实践“合法化”。

请注意,存在一些语义问题 - 结构的大小当然不会占最终成员的“灵活”大小,并且“按值”传递结构只会传递标题和第一个元素(或者没有元素)使用GCC扩展或C99灵活阵列成员)。类似地,直接结构分配不会复制所有数据。