结构体,结构体内存对齐,位段,枚举,联合知识总结

#结构体
结构体是一种自定义类型,其内部可以含多种数据类型。
例如:

struct x           //结构体标签x可以省略
{
    int num[10]; 
    char name[5];
    int age;
    
}stu,*p;       /*结构体名称stu可以省略,p是
                 结构体指针,最后的分号不可以省
                 略。*/

结构体支持嵌套,即结构体中成员仍是结构体。
###结构体成员的访问:

1,用 结构体名称 + . + 成员名称,比如 :stu.name
2,用 结构体指针 + -> + 成员名称,比如 :p->name。
###需要注意的几点:

1 . 结构体内不能包含类型为该结构本身的成员。
比如:

struct Node
{
int data;
struct Node next;
};

这样会导致Node定义时无法确定结构体的大小,修改的方法如下

struct Node
{
int data;
struct Node* next;
};

定义成指针就可以了,大小确定。

  1. 结构体可以被初始化,但不能被整体赋值,这一点与数组很像。
错误写法:
struct Node
{
int data;
char ch[10];
};
struct Node x;
x={3,"abc"};

正确写法:
struct Node
{
int data;
struct Node* next;
};
struct Node x={3,"abc"};

3.结构体嵌套初始化时要用大括号套着大括号。
比如:

struct x
{
     int a;
     int b;
};

struct Node
{
     char ch[10];
     struct x num;
     struct Node* next;
};
struct Node y={"abcde",{3,4},NULL};

#结构体内存对齐
结构体内存对齐是结构体知识的重点和难点,想理解内存对齐是怎么回事要先明白几个概念和几条原则。
1,为什么要内存对齐?
并非所有的硬件平台都能够在任何地址读取任意的数据,部分平台在某些特定的地址只能读取对应类型的数据,举个例子:比如 x平台 在0x00000001出只能读取char型的数据,但你在该地址出定义的数据的数据类型为int,就会出现报错。
所以结构体内每个成员在存储的时候都要内存对齐,为的就是保证代码的平台移植性
还有,为了读取未对齐的内存,处理器要进行两次内存访问,而对于已经对齐的内存只用进行一次内存访问。
总的来说,内存对齐就是一种用空间换时间的做法。为了节省空间,我们通常将占用内存小的成员集中在一起
2,内存对齐原则 (重点)

(1)第一个成员在与结构体变量偏移量为0的地址处。但这并不是第一个成员不用对齐。

(2). 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8 Linux中的默认值为4

(3). 结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的最小整数倍

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

以在vs环境下举几个例子:(默认对齐数为8)

struct S1
{
   char c1;
   int i;
   char c2;
};
printf("%d\n", sizeof(struct S1));

这里写图片描述
s1的第一个成员c1存在距离起始偏移量为0的地址处,占1个字节
第二个成员i自身大小为4字节,比默认对齐数8小,故i的对齐数为4。结合第二条规定,i必须存在4的整数倍地址处,故存在起始偏移量为4的地址处
同理第三个成员c2存在距起始偏移量为8的地址处。
s1最大对齐数为4,现整体长度为9,4比9大的最小倍数是12,故12为结构体s1
的大小。

struct S2
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S2));

如图: 16刚好能被8整除,故结构体s2的大小为16字节。
这里写图片描述

struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));

struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));

结构体s3的大小为16字节。 在s4中,s3的对齐数取齐内部最大对齐数8,所以s4大小为
1+7+16+8=32字节。
这里写图片描述

#位段
位段的声明和结构是类似的,有两个不同:
1.位段的成员必须是 int、 unsigned int 或signed int 。
2.位段的成员名后边有⼀个冒号和⼀个数字。
3. 位段的空间上是按照需要以4个字节(int )或者1个字节(char )的⽅式来开辟的。
4. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段。

struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
}

#枚举
顾名思义,枚举就是一一列举。
比如:

enum Day     <-枚举名称 
{
     Mon,
     Tues,
     Wed,
     Thur,   <-枚举变量,默认初值为0,依次递增1。
     Fri,
     Sat,
     Sun
};           <-分号不能少

枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 很#define定义的标识符⽐较枚举有类型检查,更加严谨。
  3. 防⽌了命名污染(封装)
  4. 便于调试

在定义枚举变量时,不能直接令其等于某个值,而应该令枚举变量的值等于原先定义的某个枚举变量。

enum Color//颜⾊
{
RED=1,
GREEN=2,
BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;

#联合
联合的概念非常好理解,即在联合体内的所有成员共享同一块内存空间,联合体的大小至少是最大成员的大小。但当最大成员的大小不是联合体最大对齐数的整数倍时,联合体的大小就要扩充至对齐数的整数倍。
⽐如:

union Un1
{
    char c[5];
    int i;
};
union Un2
{
    short c[7];
    int i;
};


Un1最大成员大小为5字节,但最大对齐数为4,故要扩充至8字节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值