sideofffect和分配位置的大小

时间:2013-02-02 13:22:37

标签: c size malloc

  

可能重复:
  Why isn’t sizeof for a struct equal to the sum of sizeof of each member?

我无法理解为什么会这样:

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

typedef struct
{
    char b;
    int a;
} A;

typedef struct
{
    char b;
} B;

int main() {
    A object;
    printf("sizeof char is: %d\n",sizeof(char));
    printf("sizeof int is: %d\n",sizeof(int));
    printf("==> the sizeof both are: %d\n",sizeof(int)+sizeof(char));
    printf("and yet the sizeof struct A is: %d\n",sizeof(object));
    printf("why?\n");

    B secondObject;
    printf("pay attention that the sizeof struct B is: %d which is equal to the "
            "sizeof char\n",sizeof(secondObject));

    return 0;
}

我想我在代码中解释了我的问题,不再需要解释了。除了我有另一个问题: 我知道在堆/静态堆/堆栈上有分配,但是这意味着分配位置是未知的,它怎么可能?

我在谈论这个例子:

    typedef struct
{
    char *_name;
    int   _id;
} Entry;

int main()
{
    Entry ** vec = (Entry**) malloc(sizeof(Entry*)*2);
    vec[0] = (Entry *) malloc(sizeof (Entry));
    vec[0]->_name = (char*)malloc(6);
    strcpy (vec[0]->_name, "name");
    vec[0]->_id = 0;
    return 0;
}

我知道: vec在堆栈上。 * vec在堆上。 * vec [0]在堆上。 vec [0] - &gt; id在堆上。

但是: vec [0] - &gt; _name未知 为什么?

4 个答案:

答案 0 :(得分:1)

在结构的构件之间和结构的末端存在未指定量的填充。在C中,结构对象的大小大于或等于其成员大小的总和。

答案 1 :(得分:0)

编译器可以在结构中自由添加填充以确保数据类型正确对齐。例如,int将与sizeof(int)个字节对齐。所以我希望A结构的大小为8。编译器执行此操作,因为从未对齐的地址获取int最好效率低下,并且最坏的情况根本不起作用 - 这取决于计算机使用的处理器。对于大多数数据类型,x86将从未对齐的地址中快速获取,但是对于获取操作,将花费大约两倍的时间。

在您的第二个代码段中,您尚未声明i

所以vec[0]->_name并不是未知的 - 它就在堆上,就像你从“malloc”(以及malloc的兄弟姐妹)得到的任何东西一样。

答案 2 :(得分:0)

如果您搜索CPU和内存对齐,请查看this question以及this one和其他许多其他内容。简而言之,如果CPU访问与它们正在读取的数据大小一致的内存,则CPU会更快乐。例如,如果您正在读取uint16_t,那么如果您读取的地址是2的倍数,则会更有效(在大多数CPU上)。为什么CPU以这种方式设计的细节是整个其他故事。

这就是为什么编译器会以额外的存储空间为代价,以最方便CPU访问它们的方式来解决并填充结构的字段。在您的情况下,假设char为4个字节,您的intint之间可能会有3个字节的填充。

如果你看一下C标准(我现在没有附近)或the man page of malloc,你会看到这样一句话:

  

malloc()和calloc()函数返回指向已分配内存的指针   适用于任何类型的变量。

这种行为正是由于我上面提到的相同原因。简而言之,内存对齐需要关注,这就是编译器在结构布局和其他地方为您做的事情,例如局部变量的布局等。

答案 3 :(得分:0)

你在这里遇到了结构填充。编译器插入可能在b中的struct A字段后插入三个字节的填充值,以便a字段是4字节对齐的。您可以使用特定于编译器的位在某种程度上控制此填充;例如,在MSVC上,GCC上的pack pragmaaligned属性,但我不建议这样做。结构填充用于指定成员对齐限制,并且某些体系结构将在未对齐访问时出错。 (其他人可能会手动修复对齐,但通常会执行此操作rather slowly。)

另请参阅:http://en.wikipedia.org/wiki/Data_structure_alignment#Data_structure_padding


关于你的第二个问题,我不确定你的名字是什么意思是“未知”。注意详细说明?