64.【C语言】再议结构体(下)(未完)

本文衔接第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;
}

 649fedba905547ce98c30e0799df9aa3.png

f592253b4fb1450b9a35f9439c373d9e.png

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标准没有规定)

解析

未存储数据时:

8b54a2c5b70741d3a0b31291363bed7c.png

分类讨论:

若按浪费空间处理

由低地址向高地址存储,设数据的二进制的存储顺序为从右向左(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

bca644ba52134c04bde9d4f35623ab84.png

 按十六进制拆分: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)

1c00e7ec857d4297977fbc51bd1b0aa2.pngde85388a6fd34fba86f07a8793c38583.png

b340dfd98b364e48a8e49e951e5cce55.png

03d67f85d9544c539904305d7925596c.png

176711e990a04735b45453832a1434b8.png

 

上一篇:Android13中Android.mk和Android.bp预编译多种架构文件


下一篇:ARM/Linux嵌入式面经(三九):中科驭数