C/C++结构体字节对齐

我就是我 2022-05-20 01:00 318阅读 0赞

稍微了解过C/C++的人,都会了解它们在建立一个结构体的时候,会进行字节对齐操作,所以往往比世界变量占用的字节数要多出一些,而如何减少内存占用,计算内存使用量,也是很多面试题里经常出现的题目。关于什么是字节对齐,如何实现字节对齐,哪些场合需要哪些场合不需要字节对齐,强烈推荐参考文章C语言字节对齐
但是稍微当我们真的不想要字节对齐的时候,有没有办法取消字节对齐?答案是可以,就是在结构体声明当中,加上attribute ((packed))关键字,它可以做到让我们的结构体,按照紧凑排列的方式,占用内存。

  1. #include <stdio.h>
  2. #include <iostream>
  3. using namespace std;
  4. struct test1 {
  5. char c;
  6. int i;
  7. };
  8. struct test2 {
  9. char c;
  10. int i;
  11. }__attribute__((__packed__));
  12. int main()
  13. {
  14. cout << "size of test1:" << sizeof(struct test1) << endl;
  15. cout << "size of test2:" << sizeof(struct test2) << endl;
  16. }

输出结果:

  1. size of test1:8
  2. size of test2:5

下面的示例能更清楚地说明这种现象:

  1. #include<stdio.h>
  2. typedef struct{
  3. char c1;
  4. short s;
  5. char c2;
  6. int i;
  7. }T_FOO;
  8. int main(void){
  9. T_FOO a;
  10. printf("c1:%x\ns:%x\nc2:%x\ni:%x\n",&a.c1,&a.s,&a.c2,&a.i);
  11. printf("c1 -> %d\ts -> %d\tc2 -> %d\ti -> %d\n",
  12. (unsigned int)(void *)&a.c1 - (unsigned int)(void *)&a,
  13. (unsigned int)(void *)&a.s - (unsigned int)(void *)&a,
  14. (unsigned int)(void *)&a.c2 - (unsigned int)(void *)&a,
  15. (unsigned int)(void *)&a.i - (unsigned int)(void *)&a);
  16. return 0;
  17. }

输出结果:

  1. c1:60ff38
  2. s:60ff3a
  3. c2:60ff3c
  4. i:60ff40
  5. c1 -> 0 s -> 2 c2 -> 4 i -> 8

上例中,结构体中变量默认按照最长的int型变量 i 即4字节对齐,所以char型变量c1实际上只有1个字节,但是后面的short型变量s并没有马上紧挨着c1排列,而是为了4字节对齐,中间空了一个字节内存,后面的c2同理也是如此。

  1. #include<stdio.h>
  2. typedef struct {
  3. char c1;
  4. short s;
  5. char c2;
  6. int i;
  7. }T_FOO;
  8. int main(void) {
  9. T_FOO a;
  10. a.c1 = 'a';
  11. a.s = 100;
  12. a.c2 = 'b';
  13. a.i = 1000;
  14. printf("size of T_FOO a:%d\n ", sizeof(a));
  15. printf("c1: %c\n", a.c1);
  16. printf("behind c1: %x\n", *(&a.c1 + 1));
  17. printf("s: %d\n", a.s);
  18. printf("c2: %c\n", a.c2);
  19. printf("behind c2: %x\t%x\t%x\t\n", *(&a.c2 + 1), *(&a.c2 + 2), *(&a.c2 + 3));
  20. printf("i: %d\n", *((int *)(&a.c2 + 4)));
  21. return 0;
  22. }
  23. size of T_FOO a:12
  24. c1: a
  25. behind c1: 30
  26. s: 100
  27. c2: b
  28. behind c2: 30 40 0
  29. i: 1000

另外,还有如下的一种方式:
· __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
· attribute ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

例1
struct test
{
char x1;
short x2;
float x3;
char x4;
};

由于编译器默认情况下会对这个struct作自然边界(有人说“自然对界”我觉得边界更顺口)对齐,结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然边界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4字节对界,是该结构所有成员中要求的最大边界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间为12字节。

例2

pragma pack(1) //让编译器对这个结构作1字节对齐

struct test
{
char x1;
short x2;
float x3;
char x4;
};
pragma pack() //取消1字节对齐,恢复为默认4字节对齐
这时候sizeof(struct test)的值为8。

例3

define GNUC_PACKED attribute((packed))

struct PACKED test
{
char x1;
short x2;
float x3;
char x4;
}GNUC_PACKED;

这时候sizeof(struct test)的值仍为8。

  1. #include <stdio.h>
  2. main()
  3. {
  4. struct A {
  5. int a;
  6. char b;
  7. short c;
  8. };
  9. struct B {
  10. char b;
  11. int a;
  12. short c;
  13. };
  14. #pragma pack (2) /*指定按2字节对齐*/
  15. struct C {
  16. char b;
  17. int a;
  18. short c;
  19. };
  20. #pragma pack () /*取消指定对齐,恢复缺省对齐*/
  21. #pragma pack (1) /*指定按1字节对齐*/
  22. struct D {
  23. char b;
  24. int a;
  25. short c;
  26. };
  27. #pragma pack ()/*取消指定对齐,恢复缺省对齐*/
  28. int s1=sizeof(struct A);
  29. int s2=sizeof(struct B);
  30. int s3=sizeof(struct C);
  31. int s4=sizeof(struct D);
  32. printf("%d\n",s1);
  33. printf("%d\n",s2);
  34. printf("%d\n",s3);
  35. printf("%d\n",s4);
  36. }

输出

  1. 8
  2. 12
  3. 8
  4. 7

发表评论

表情:
评论列表 (有 0 条评论,318人围观)

还没有评论,来说两句吧...

相关阅读

    相关 结构字节对齐

    /\ 结构体变量占据的内存单元的个数应当大于等于其内部所有的数据成员占据内存单元数据的和 \/ /\ 出于效率的考虑,C语言引入了对齐机制,一般来说,不同的编译器字节对

    相关 C++结构字节对齐

    前言 在计算机中数据存储和传输以位(bit)为单位,每8个位bit组成1个字节(Byte)。32位计算机的字长为32位,即4个字节;对应的,64位计算机的字长为64位,

    相关 结构字节对齐

    在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何变量的访问都可以从任何地址开始访

    相关 C/C++结构字节对齐

    稍微了解过C/C++的人,都会了解它们在建立一个结构体的时候,会进行字节对齐操作,所以往往比世界变量占用的字节数要多出一些,而如何减少内存占用,计算内存使用量,也是很多面试题里