19

C语言结构体大小等于它的所有成员大小之和吗?

 3 years ago
source link: https://blog.popkx.com/c%E8%AF%AD%E8%A8%80%E7%BB%93%E6%9E%84%E4%BD%93%E5%A4%A7%E5%B0%8F%E7%AD%89%E4%BA%8E%E5%AE%83%E7%9A%84%E6%89%80%E6%9C%89%E6%88%90%E5%91%98%E5%A4%A7%E5%B0%8F%E4%B9%8B%E5%92%8C%E5%90%97/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C语言结构体大小等于它的所有成员大小之和吗?

发表于 2019-08-12 20:08:37   |   已被 访问: 364 次   |   分类于:   C语言   |   暂无评论

结构体在C语言程序开发中,是不可或缺的语法。不过,相信不少C语言初学者遇到过这样的问题:为什么结构体的 size 有时不等于它的所有成员的 size 之和呢?

C语言结构体大小等于它的所有成员大小之和吗?

举例来说,假设有结构体,它的C语言代码如下,请看:

struct x{
    short s;
    int i;
    char c;
};

我们继续编写C语言代码,依次输出成员 s,i,c 占用内存空间的大小,相关代码很简单,请看:

struct x t;
printf("%lu %lu %lu\n", sizeof(t.s), sizeof(t.i), sizeof(c));

编译并执行这段C语言代码,得到如下输出:

# gcc t.c 
# ./a.out 
2 4 1

那么按理说,结构体 x 占用的内存空间应该等于 2+4+1=7 字节,但是似乎实际结果与我们的预期并不一致:

printf("%lu\n", sizeof(t));

上面这行C语言代码输出的结果是 12!这是怎么回事呢?

程序输出的结果与我们的预期不一致,原因在于“对齐机制”。如果将结构体 x 看作是一个容器,鉴于成员 s,i,c 的长度参差不齐,C语言编译器不得不“填充”一些额外的空间,以满足“对齐机制”。

数据结构是否对齐不仅影响C语言程序的性能,有时甚至还会带来意想不到的错误,例如访问未对齐的数据,可能会导致硬件方面的问题 (SIGBUS,总线错误),导致性能下架,以及破坏一些操作的原子性等并发安全保障。

所以,C语言编译器在处理结构体时,如果没有特别的指定,一般都会填充一些字节,以确保不违背对齐机制。以上面的结构体 x 为例,初学者可能会认为它的成员在内存中的布局如下:

a0a5b1d5ca0f40f1f25076924f073b4c.png

但是,如果编译器按照下面布局,处理器访问之将更加方便:
2a183159d02da7e28ef572a2e1f8c953.png
不过,这样排列结构体 x 的成员,会空出一些空间,对于处理器来说,小心的跳过这些空间还是有些麻烦,于是大多数C语言编译器都会像下面这样填充空穴:
431fe09893c3d728a6295e9169c80659.png
这样一来,整个结构体 x 占用内存的空间,其实就是成员 i 占用空间的 3 倍了,也即 12 字节。

事实上,我们可以通过排列结构体 x 成员的顺序,来优化其占用内存的大小,例如:

struct y{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
    short s; /* 2 bytes */
};

struct z{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
};

const int sizeX = sizeof(struct x); /* = 12 */
const int sizeY = sizeof(struct y); /* = 8 */
const int sizeZ = sizeof(struct z); /* = 8 */
e24d6d870dfc6f8897d2ac896246eff8.png

本节主要讨论了C语言中结构体大小并不一定等于它所有成员大小之和的原因,应该注意,结构对齐在C语言标准中是 implementation defined,不同的C语言编译器可能选择不同的数据对齐方式,从而导致不同和不兼容的数据布局。因此,在使用不同编译器开发C语言程序时,了解编译器是如何对齐数据是很重要的。

一些编译器可以指定结构对齐的方式,例如 #pragma 语句。

阅读更多:   C语言


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK