本文衔接第63篇
目录
6.复习
7.修改默认对齐数
8.结构体传参
01.传递非指针参数
02.传递指针参数(传递地址)
03.对比
9.结构体实现位段
01.位段的定义
02.格式
03.例题
答案速查
分析
前置知识:位段的内存分配
解析
若按浪费空间处理
验证
6.复习
20.【C语言】初识结构体(重要)
48.【C语言】结构体补充
63.【C语言】再议结构体(上)
7.修改默认对齐数
加一条预处理指令
#pragma pack(对齐数)
struct 结构体标签
{
成员列表;
}变量列表(全局变量);//变量列表可以不写,但;必须有!!!
在#pragma pack(对齐数)后紧跟着结构体就能指定该结构体的对齐数
建议给1,2的次方数:2,4,8
#include <stdio.h>
#pragma pack(1)
struct s1
{
char a;
char b;
int c;
};
#pragma pack()//恢复默认对齐数
int main()
{
printf("%zd", sizeof(struct s1));
return 0;
}
打印结果为6
8.结构体传参
01.传递非指针参数
#include <stdio.h>
struct s
{
int data[1000];
int num;
};
void sim_print(struct s ss)//结构体传参
{
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ",ss.data[i]);
}
printf("\nnum = %d\n", ss.num);
}
int main()
{
struct s s = { { 1, 2, 3, 4, 5 } , 100 };
sim_print(s);
return 0;
}
02.传递指针参数(传递地址)
#include <stdio.h>
struct s
{
int data[1000];
int num;
};
//结构体传参,*ps表明传递的是指针
void sim_print(struct s *ps)
{
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ",ps->data[i]);
}
printf("\nnum = %d\n", ps->num);
}
int main()
{
struct s s = { { 1, 2, 3, 4, 5 } , 100 };
sim_print(&s);//传的是地址
return 0;
}
注:结构体成员变量->成员名是结构体特有的写法
03.对比
当结构体成员变量占用较大的内存时, 因为参数要压栈,所以传递指针参数比传递非指针参数要节省空间,传递指针参数不会另外开辟额外的空间
9.结构体实现位段
01.位段的定义
摘自百度百科:
C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”(bit field),利用位段能够用较少的位数存储数据
02.格式
类型 成员变量:数字;
如: int a:5;
03.例题
求下列代码的执行后位段在内存中的数据(在VS2022中测试)
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;
}
答案速查
位段在内存中的数据:62 03 04
分析
因为 以位为单位来指定其成员所占内存长度
前置知识:位段的内存分配
2条规则,1条提醒
1.位段的成员可以是int,unsigned int,signed int,char等类型
2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的
提醒:位段涉及很多不确定因素,位段不跨平台,注重可移植的程序应该避免使用位段(本文后面会单独讲)
位段的内存分配
1.数据的存储顺序由是编译器而定(C标准没有规定)
2.每次向CPU申请1byte,如果不够则继续申请1byte
3.是否浪费空间取决于编译器(C标准没有规定)
解析
未存储数据时:
分类讨论:
若按浪费空间处理
由低地址向高地址存储,设数据的二进制的存储顺序为从右向左(VS2022满足此情况)
十进制10==二进制1010 十进制12==二进制1100 十进制3==二进制11 十进制4==二进制100
char a : 3;-->a占3位,1010会被截断为低3位010存储
char b : 4;-->b占4位,恰好可以存储1100
char c : 5;-->c占5位,11占2位,因此补前导零存储为00011
char d : 4;-->d占4位,100占3位,因此补前导零存储为0100
按十六进制拆分:0110 0010 0000 0011 0000 0100-->62 03 04
位段的空间以4个字节(int)或者1个字节(char)的方式来开辟的,a,b,c,d的类型全为char,因此不用改动为62 03 04 00
验证
VS2022+x64+debug环境下,VS2022调试,F11逐语句
打开内存窗口,输入&s(小写的s)