内存对齐与内存开辟。结构体(struct),位段,枚举类型(enum),联合体(union)。

简介: 内存对齐与内存开辟。结构体(struct),位段,枚举类型(enum),联合体(union)

1.结构体内存对齐

(1)结构体内存对齐规则


a.第一个成员在与结构体变量偏移量为0的地址处


b.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处


对齐数=编译器默认对齐数与该成员大小的较小值.


vs中默认值为8(如果没有默认对齐数 则默认对齐数为成员大小本身)


c.结构体总大小为最大对齐数的整数倍


d.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体大小就是所有最大对齐数(含嵌套结构体)的整数倍


(2)举例:

a.

int main()
{
  struct S1
  {
    char c1;  //1 8 对齐数为1  1字节
    int i;    //4 8 对齐数为4 要在偏移量4的整数倍处开辟 浪费3个字节 8字节
    char c2;  //1 8 对齐数为1  9字节 最后结构体大小要为最大对齐数4的整数倍 所以又浪费3字节 12字节
  };
  struct S1 s;
}

b.

#include<stdio.h>
int main()
{
  struct S2
  {
    char c1;//1 8 对齐数为1 1字节
    char c2;//1 8 对齐数为1 2字节
    int i;  //4 8 对齐数为4 要在偏移量为对齐数的整数倍处开辟 浪费两个字节 8字节
  };
  struct S2 s;
}

c.

int main()
{
  struct S3
  {
    double d;// 8 8 对齐数为8 8字节
    char c;  // 1 8 对齐数为1 9字节
    int  i;  // 4 8 对齐数为4 在12处开辟 16字节
  };
  struct S3 s;
}

d.

int main()
{
  struct S3
  {
    double d;// 8 8 对齐数为8 8字节
    char c;  // 1 8 对齐数为1 9字节
    int  i;  // 4 8 对齐数为4 在12处开辟 16字节
  };
  struct S4
  {
    char c1;     //1 8 对齐数为1 1字节
    struct S3 s3;//8 8 嵌套结构体对齐数为内结构体的最大对齐数8 在8处开辟8+16=24
    double d;    //8 8 对齐数为8 8+24=32 32字节 结构体大小为最大对齐数的整数倍
  };
  struct S4 s;
  
}

(3)内存对齐的原因


a.平台原因(移植原因)


不是所有的硬件平台都能访问任意地址上的任意数据。


b.性能原因


为了访问未对齐的内存,处理器要做两次内存访问。而对齐后的内存,处理器只需要访问一次。


(4)总结


如果要使结构体尽可能少的浪费空间,我们需要让占用空间小的成员尽量集中在一起。

2.位段

1.什么是位段?

位段的声明和结构体是类似的,用两个不同:

a.位段的成员必须是:int ,unsigned int,signed int,char , unsigned char。

b.位段的成员名后边有一个冒号和一个数字。

int main()
{
  struct A
  {
    int _a : 2; //_a这个成员只占2个bit位 只能表示0 1 2 3
    int _b : 5; //_b这个成员只占5个bit位
    int _c : 10;
    int _d : 30;
  };
}

2.位段的空间是按照需要以4个字节或一个字节来开辟的

3.弊端:位段是不跨平台的.

3.枚举(一一列举)

利用枚举类型定义常量(比宏定义有优点)

int main()
{
  enum Color
  {
    RED = 5,
    GREEN = 8,
    BULE
  };          //一次可以定义多个常量
}

4.联合(共用体)

这些成员共用一块空间(同一时间只能使用一个!)

int main()
{
  union Un
  {
    char c;//c用的是i的第一个字节的空间
    int i; 
  };
  union Un un; //联合体大小至少是最大成员的大小
}

1.联合体的大小(要对齐)

int main()
{
  union Un
  {
    short arr[7];// 14 2 
    int i;//4   4  
    }u;//本来14个一节就够了 但是联合体需要对其 
      //到最大对齐数4的整数倍 所以为 16个字节
}

2.利用联合体判断大小端

#include<stdio.h>
int main()
{
  union Un
  {
    char c;
    int i;
  }u;
  u.i = 1;
  if (u.c == 1)
  {
    printf("小端\n");
  }
  else
  {
    printf("大端\n");
  }
}


目录
相关文章
|
1月前
|
编译器 C语言 C++
【C语言】realloc()函数详解(动态内存开辟函数)
【C语言】realloc()函数详解(动态内存开辟函数)
33 0
|
1月前
|
编译器 C++
C/C++动态内存开辟(详解)
C/C++动态内存开辟(详解)
|
7月前
|
编译器 C语言 C++
C/C++内存对齐规则(结构体、联合体、类)
C/C++内存对齐规则(结构体、联合体、类)
|
1月前
|
存储 编译器 Linux
匿名结构体类型、结构体的自引用、结构体的内存对齐以及结构体传参
匿名结构体类型、结构体的自引用、结构体的内存对齐以及结构体传参
|
6天前
|
C语言
动态内存开辟(下)
动态内存开辟(下)
8 0
|
6天前
|
编译器 C语言
动态内存开辟(上)
动态内存开辟(上)
7 0
|
11天前
|
C语言
C语言学习记录——动态内存开辟常见的错误
C语言学习记录——动态内存开辟常见的错误
9 1
|
11天前
|
编译器 Linux C语言
C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)二
C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)二
17 1
|
11天前
|
存储 编译器 C语言
C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)一
C语言学习记录——结构体(声明、初始化、自引用、内存对齐、结构体设计、修改默认对齐数、结构体传参)一
20 2
|
21天前
关于动态开辟内存的经典笔试题
关于动态开辟内存的经典笔试题
18 0

热门文章

最新文章