0

可能重复:
为什么结构的 sizeof 不等于每个成员的 sizeof 之和?

我不明白为什么会这样:

#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]->id 在堆上。

但是: vec[0]->_name 不知道为什么?

4

4 回答 4

1

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

于 2013-02-02T13:26:10.100 回答
0

编译器可以自由地在结构中添加填充以确保数据类型正确对齐。例如, anint将与sizeof(int)字节对齐。所以我希望你的A结构大小的输出是8. 编译器会这样做,因为int从未对齐的地址中获取一个充其量是低效的,最坏的情况是根本不起作用——这取决于计算机使用的处理器。对于大多数数据类型,x86 将愉快地从未对齐的地址中提取,但提取操作需要大约两倍的时间。

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

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

于 2013-02-02T13:29:20.447 回答
0

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

这就是为什么编译器会来救援并以一种最适合 CPU 访问它们的方式填充结构的字段,但代价是额外的存储空间。在您的情况下,您可能会在charand之间获得 3 个字节的填充int,假设int是 4 个字节。

如果您查看 C 标准(我现在附近没有)或malloc 的手册页,您会看到这样一个短语:

malloc() 和 calloc() 函数返回一个指向已分配内存的指针,该指针适合任何类型的变量对齐。

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

于 2013-02-02T13:32:09.630 回答
0

您在这里遇到了结构填充。b编译器可能会在 in的字段之后插入三个字节的填充struct A,以便该a字段是 4 字节对齐的。您可以使用特定于编译器的位在某种程度上控制此填充;例如,在 MSVC、pack pragmaalignedGCC 上的属性,但我不建议这样做。结构填充用于指定成员对齐限制,并且某些架构会在未对齐访问时出错。(其他人可能会手动修复对齐,但通常这样做会相当缓慢。)

另见:http ://en.wikipedia.org/wiki/Data_structure_alignment#Data_structure_padding


至于你的第二个问题,我不确定你所说的“未知”是什么意思。需要详细说明吗?

于 2013-02-02T13:33:05.883 回答