c语言-结构体在内存中的存放形式
第一篇博客,请大家多多包涵!
结构体在内存中的存放形式:
使用sizeof()运算符计算结构体在内存中所占用的字节数很明显可以看到与实际声明类型的字节数不同。(sizeof() 是用来计算类型在内存中所占字节数的大小)
对于刚入门的同学肯定会很疑惑,结构体在内存中到底是怎样存放的呢?
-
首先说明一个概念-字节对齐
这个概念有很多叫法,这里我们就叫字节对齐。字节对齐就是数据类型按照固定的字节大小排列,方便计算机cpu、内存等的读取。结构体中的数据类型并不是都相同的,这个时候就需要字节对齐来提高计算机的读取效率。 -
结构体会进行字节对齐,默认情况下字节对齐的单位是当前结构体体中非构造类型所占最大字节数。
可能我描述的有点绕,简单来说就是:你在结构体中描述了int 和 char类型,那么编译器(本人用的是gcc编译器,不同编译器可能会有差异)会默认对齐单位是int所占字节数,如果加上double类型,那么默认为8字节。 -
连续的数据类型所占字节数如果加起来不大于对齐单位,则会放在一起读取,否则就会把位置预留出来。
比如:结构体描述了int 和 2个连续的char类型,默认情况下,总共占用8字节;int占4字节,每个char占用2字节,剩余两个字节空出来。但是这两个空出来的空间属于结构体的,其他变量无法写入,算是废弃空间。如果是自学的话,这一点可能会忽略,导致看不懂结构体的存储方式,下面我会使用一些简单的例子来验证。 -
通过一些预编译手段来自定义对齐单位
pragma pack(n) 预编译实现,自定义设置对齐单位,其中n只能是2的次方且不能超过构造体内非构造类型所占最大字节数(超过则n无效)。
struct NAME{构造描述}attribute((packed)); 如果是gcc编译器可以使用 attribute((packed)) 指令告诉编译器取消字节对齐,这条指令是gcc编译器特有的。
用几个小例子就可以发现结构体在内存中存放的规律:
- test1
struct test1_st
{
int i;
char c;
};
int main()
{
struct test1_st test1 = {};
printf("%lu\n",sizeof(test1));
}
运行结果:
8
很明显一个int加一个char类型占的应该是5个字节,在结构体中却是8字节。说明存在字节对齐。
- test2
struct test2_st
{
int i;
char c;
char c2;
};
int main()
{
struct test2_st test2 = {};
printf("%lu\n",sizeof(test2));
}
运行结果:
8
这次我只是在结构体中多加了一个char类型,可他们占用的还是8字节。说明:连续的数据类型所占字节数如果加起来不大于对齐单位,则会放在一起读取!我们可以把他们的顺序调整一下。
- test3
struct test3_st
{
char c;
int i;
char c2;
};
int main()
{
struct test3_st test3 = {};
printf("%lu\n",sizeof(test3));
}
运行结果:
12
我们这次把char c 调到了顶部,char c 与 char c2 已经不是连续的了。这时查看运行结果为 12 ,证明了上述理论。
- 小例子就这些,大家可以使用不同的类型来尝试一下,如果发现与我论述内容有不同的地方,或者是文中的错误,都可以评论告之。
还有自定义或取消对齐单位,主要是用于数据传输,毕竟不同平台可能存储略有差异,万一传输内容都是废弃空间,那岂不是很尴尬!