目录
一.结构体的声明
1.结构的声明
2.结构体变量的创建和初始化
3.结构的特殊声明
4.结构体的自引用
二.结构体内存对齐(计算结构体大小)
1.对齐规则
2.修改默认对齐数
3.结构体传参
三.结构体实现位段
1.位段
2.位段的内存分配
3,位段的注意事项
下面代码演示的是取地址操作的注意事项:
4.实际应用场景
拓展:
网络协议中的典型应用
完
struct stu {
char name[20];
int age;
char sex[5];
char id[20]
};
#include
struct Stu {
char name[20];
int age;
char sex[5];
char id[20]
};
int main() {
struct Stu s1 = { "zhangsan",20,"nan","20211111" };
struct Stu s2 = {.age = 20,.name = "lisi",.id = 20231111,.sex = "nan"};
return 0;
}
匿名结构体类型
struct {
int a;
char b;
float c;
}x;
匿名的结构体类型结构,如果没有对结构体类型重命名,则在结构体后创建的x只能使用一次
struct node {
int data;
struct node* next;
};
①结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处
②从第二个成员变量开始,都要对齐到对齐数的整数倍处
对齐数 = 编译器默认的一个对齐数和该成员变量大小的较小值
vs中默认对齐数为8,gcc中没有默认对齐数
③结构体的总大小为最大对齐数的整数倍
④如果嵌套了结构体,嵌套的成员对齐到自己成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数
#pragma pake(1); :设置默认对齐数为1
#pragma pake(); :取消设置的对齐数,还原为默认
#include
struct S {
int data[100];
int num;
};
struct S s = { {1,2,3,},100 };
void My_printf(struct S* ps){
printf("%d\n", ps->num);
}
int main() {
My_printf(&s);
return 0;
}
结构体传参时,要传递结构体的地址
位段(Bit Field)是结构体中一种特殊的成员,允许以位为单位指定成员所占的内存空间。这种机制常用于节省存储空间或直接访问硬件寄存器中的特定位。
struct 结构体名 {
数据类型 成员名 : 位宽;
};
数据类型:通常为 int
、unsigned int
或 _Bool
(C99 引入)。其他类型可能因编译器而异。
位宽:指定成员占用的位数,必须为非负整数且不超过数据类型本身的位数。
成员名后面加上冒号和数字。
例如:
struct A {
int _a : 2;
int _b : 5;
int c : 10;
};
①位段的类型可以是int,unsigned int,signed int,char类型。
②位段的空间上是按照需要,以四个字节(int)或一个字节(char)的方式来开辟的。
③位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段,
例如:
#include
struct S {
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
int main() {
struct S s = { 0 };
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
return 0;
}
开辟空间演示:
在vs中,一个字节的内部,内存是从右向左使用的(避免剩余空间的浪费)。
先在低地址处创建一个字节内存大小,在内存内部中的右侧开辟a的空间(三个比特位),由于在第一次开辟的一个字节内存中还有剩余空间并且大小能够被b(四个比特位)使用,因此在a 的右边存放b。c(五个比特位),第一次开辟的空间不够,因此在较高地址处新开辟一个字节的空间,用来存放c;以此类推。
内存对齐:位段成员的实际布局受编译器对齐规则影响,不同平台可能有差异。
跨平台兼容性:位段的存储顺序(高位优先或低位优先)由编译器决定,涉及跨平台时需谨慎。
取地址操作:无法对位段成员使用取地址运算符 &
,因为其可能不按字节边界对齐
由于位段成员可能共用一个字节,这样有些成员的起始位置不是该成员的起始位置 ,那么这些位置处是没有位置的。(内存中每个字节分配一个地址,一个字节的内部bit位是没有地址的)
所有不能对位段成员使用&操作符,这样就不能使用scanf直接给位段的成员输入值,只能先输入放在一个变量中,然后赋值给位段的成员。
#include
struct S {
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 20;
};
int main() {
struct S s = { 0 };
//scanf("%d",&s.b);这是错误的写法
//正确写法
int b = 0;
scanf("%d", &b);
s._b = b;
return 0;
}