ui动效网站,男人的天堂哔哩哔哩,2020互联网公司排名,erp沙盘模拟实训报告目录
一、结构体的类型的声明
二、结构体变量的创建和初始化
三、匿名结构体类型
四、结构体自引用
五、结构体内存对齐
#xff08;1#xff09;对齐规则
#xff08;2#xff09;计算结构体大小练习
#xff08;3#xff09;需要内存对齐的原因
#xff08;4…目录
一、结构体的类型的声明
二、结构体变量的创建和初始化
三、匿名结构体类型
四、结构体自引用
五、结构体内存对齐
1对齐规则
2计算结构体大小练习
3需要内存对齐的原因
4修改默认对齐数
六、结构体传参
七、结构体实现位段
1什么是位段
2位段的内存分配
3位段的跨平台的问题
4位段的应用
5位段不能使用取地址符 一、结构体的类型的声明 形式如下
struct tag
{member - list; // 成员列表
}variable - list; // 变量列表属于全局变量也可以没有 例如定义一个学生结构体类型并创建了全局变量s1
struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
}s1;
二、结构体变量的创建和初始化
// struct Stu 类型的定义
struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
};
int main()
{//按照结构体成员的顺序初始化struct Stu s { 张三, 20, 男, 20230818001 };printf(name: %s\n, s.name);printf(age : %d\n, s.age);printf(sex : %s\n, s.sex);printf(id : %s\n, s.id);//按照指定的顺序初始化struct Stu s2 { .age 18, .name lisi, .id 20230818002, .sex ⼥ };printf(name: %s\n, s2.name);printf(age : %d\n, s2.age);printf(sex : %s\n, s2.sex);printf(id : %s\n, s2.id);return 0;
}
三、匿名结构体类型 省略掉结构体标签 (tag)
struct
{int a;char b;float c;
}x;struct
{int a;char b;float c;
}a[20], * p; 因为匿名结构体类型没有名字所以如果没有对匿名结构体重命名的话只能使用一次创建一次变量即声明结构体类型的时候就创建。并且两个成员相同的匿名结构体类型不相同如下 四、结构体自引用 结构体中不能包含同类型的结构体成员。因为结构体类型还没完全声明结束就开始使用同类型是不行的不清楚它的大小相当于一个类型还不存在的时候就开始使用这个类型并且仔细想想这样声明的结构体的大小是无穷大的如下 如果结构体想自引用同类型只能定义为指针类型。指针类型是内置类型本来就存在大小也可知4 或 8字节如下
struct Node
{int data;struct Node* next;
}; 如果是对匿名结构体重命名就算是包含同类型的指针类型也是不行的因为在重命名 Node 之前都还不知道这个匿名函数叫啥就使用 Node 的指针如下 因此结构体自引用不能使用匿名结构体改为如下就正确了
typedef struct Node
{int data;struct Node* next;
}Node;五、结构体内存对齐 是计算结构体大小的规则。
1对齐规则
① 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处。
② 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 编译器默认的一个对齐数与该成员变量大小的较小值。 VS 中默认的值为 8。 Linux中 gcc 没有默认对齐数对齐数就是成员自身的大小。
③ 结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数所有对齐数中最大的) 的 整数倍。
④ 如果嵌套了结构体的情况嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
2计算结构体大小练习
练习一 结构体S1的大小 结构体S2的大小 S1 和 S2 类型的成员一模一样但是 S2 比 S1 占的空间更小是因为变量 c1 和 c2是放在一起的。因此让占用空间小的成员尽量集中在一起更节省空间。
练习二 结构体S3的大小 结构体S4的大小 3需要内存对齐的原因
① 平台原因移植原因 不是所有的硬件平台都能访问任意地址上的任意数据某些硬件平台只能在某些地址处取某些特定类型的数据比如 int 类型数据只能在固定地址处存取否则抛出硬件异常。为了提高代码的可移植性对所有硬件平台都适用需要内存对齐。
② 性能原因 访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要一次访问。比如对于结构体 s
struct s{char c;int i;
}; 如果内存不对齐 如果内存对齐 32位机器上数据总线是32根读、写数据的时候一次就读/写32位(4个字节)。如果不对齐要读两个字节才能拼凑出 i如果对齐发现第一个字节没有直接跳到第二个字节读取一次就可以得到 i 。因此内存对齐更能节省读取时间用空间换时间。
4修改默认对齐数 使用 #pragma 预处理指令示例
#pragma pack(1)//设置默认对⻬数为1
struct S
{char c1;int i;char c2;
};
#pragma pack()//还原为默认对齐数 对齐数通常是 2 的 x 次方如 1248不能随意设置。
六、结构体传参 一种是传结构体本身一种是传结构体的地址如下
struct S
{int data[1000];int num;
};
struct S s { {1,2,3,4}, 1000 };//结构体传参
void print1(struct S s)
{printf(%d\n, s.num);
}//结构体地址传参
void print2(struct S* ps)
{printf(%d\n, ps-num);
}int main()
{print1(s); //传结构体print2(s); //传地址return 0;
} 因为函数传参参数要压栈会有空间和时间上的系统开销。如果结构体比较大传结构体本身开销就比较大如果传结构体地址指针只有 4 个字节开销就比较小。因此结构体传参最好传地址。
七、结构体实现位段
1什么是位段 与结构体类似但有两个不同 成员类型必须是 int、unsigned int、signed int、charC99 标准中也可以是其它类型。 成员名后是 冒号 数字。 形式如下
struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
}; 位段 A 大小是如果按照结构体的内存对齐的方法计算4 * 4 16 个字节。看看运行结果 显然不是按结构体的方式计算内存大小实际上位段的位表示二进制位冒号后面的数字是该成员的大小比如 _a 占 2 bit 。但是位段 A 的所有成员的大小加起来是 251030 47用 6 个字节68 bit就够了为什么是8 字节呢请看下节。
2位段的内存分配
位段每次开辟 4 个字节int或者 1 个字节char。位段的不确定因素很多比如每次开辟从左还是右存储每次开辟的空间不够下一个成员使用剩余的空间要不要接着使用不可跨平台注重可移植性的代码要避免用位段。 如下例子
struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};int main()
{struct S s { 0 };printf(%d\n, sizeof(s));s.a 10;s.b 12;s.c 3;s.d 4;return 0;
} VS中的规则 char 类型每次开辟一个字节。 一个字节内从右向左使用。 一个字节内剩余的 bit 不够下一个成员使用浪费掉并开辟新的一个字节存放。 定义结构体变量 s 并初始化位段成员值为 0开辟如下的空间因为位段是 char 类型每次开辟 1 个字节空间 一共是3个字节。再给所有位段成员赋值超出的截断不够的补0 调试验证每 4 bit 是一个十六进制数那么上面的值用十六进制表示就是62 03 04 调试结果与理论一致 运行结果 解决1中遗留的问题
struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
}; 因为位段成员是 int 类型所以每次开辟 4 个字节一共开辟了 8 个字节 3位段的跨平台的问题 int 位段被当成有符号还是无符号数是不确定的。 位段中最大的数目不确定。32位机器最大位是3216位机器最大位是16。如果是16位机器像下面这样写就是错误的因为 30 位已经超过了最大的 16 位但在 32 位机器上是正确的。
struct S
{int a : 30;
};
每次开辟的空间是从左向右还是从右向左使用是不确定的。每次开辟的空间剩余的空间不够下一个位段成员使用时是浪费掉还是接着使用是不确定的。
总结位段可以设置使用的位比结构体固定的字节更节省空间但存在跨平台的问题。
4位段的应用 数据在网络上传输需要遵守网络协议网络协议中有个IP数据报的概念相当于快递包裹上的各种邮寄信息有发件人、收件人才知道包裹从哪发、发给谁下面就是IP数据报的格式 如果不用位段版本4位是整型分配 4 个字节空间就会浪费 28 位空间。可以发现每一行信息需要的空间加起来刚好是 32 位4 个字节刚好是一个整型的大小设计成位段将会没有一点空间浪费。 IP数据报追求节省空间因为使用更小的空间网络越通畅。
5位段不能使用取地址符 位段中几个成员共用一个字节而内存中是按字节编址的所以一个字节内的 bit 没有地址就不能对位段成员取地址如下会报错 因此不能使用 scanf 直接给位段成员输入值只能先输入值放在变量中变量再赋值给位段成员