C学习:自定义类型-1.10

学习内容:

一. 内存函数

  1. memcpy()内存拷贝函数的局限性是只能拷贝内存不重叠的内容。对此,使用memmove()应对内存重叠的情况。
    (这里我先想的是把预先拷贝的源地址的内容取出来保存下来,再用这些保存下来的数据替换到目的地址。但是这样是浪费了内存空间。解决方法:可以利用从后往前,或者从前往后的移动顺序规避内存重叠问题,使移动的数据还是原始数据。)

二. 自定义类型

1.结构体

a. 匿名结构体

普通结构体格式:

struct tag
{
成员变量;
}结构体变量名;

匿名结构体格式:(只知道是个结构体,但是标签tag不知道)

struct 
{
成员变量;
}结构体变量名;

(有什么用呢?不能同时用两个匿名结构体,而且这样写起来看起来也很麻烦。)

b. 结构体自引用

这里提及了数据结构里链表的概念,一块内存既有数据又有下个内存的地址,这样顺序寻找,直到最后一块内存为空指针。(和fragment的切断和重组类似)
既有数据又有下个内存的地址

struct N
{
	char b;
	int a;
	struct N* next; 指向同类型不同的结构体,包含别的结构体的地址(指针)
};
c. 结构体内存对齐

原因:
1)硬件问题,有的硬件不能访问任意地址(可能只能4个字节4个字节访问),内存对齐后才好访问。
2)性能原因,不对齐,在取用数据的时候需要读取多次,牺牲内存空间换取效率。
内存对齐规则:
1)结构体第一个成员就放第一个,即相对坐标为0的地址处。
2)对齐数是每个平台自带的一个参考数值,将对齐数与第二个开始的成员变量的字节大小比较,取较小的值的整数倍的相对坐标作为该成员变量的开始地址。(假设平台参考对齐数为8,你的变量为整型int a,4个字节,其中4<8,取4的倍数作为int a的开始地址,因为char b占了一个字节,则int a不能从0开始,只能从4开始)
3)结构体整体大小为所有成员变量对齐数中的最大值的整数倍。
4)当结构体内嵌套结构体,嵌套的要对齐自身最大对齐数的整数倍处。
修改参考对齐数:

#pragma pack(2);设置参考对齐数为2

2.位段(预留位置)

a.结构

1)成员必须是int,unsigned int,或signed int类型。
2)成员后有一个冒号和数字

struct A
{
	int a:2;  给a预留两个bit位
	int b:3;  给b预留三个bit位
	int c:5;
}:
b. 内存占用

int a开了32bit的空间,但是a只用了2bit,于是int b就直接使用a开的32bit剩下的位置。c不确定。
例子:

struct A x={0};
x.a=11; 二进制10112bit,11存入开辟的32bit的第一个字节内。
x.b=3;  二进制0113bit,011存入开辟的32bit的第一个字节剩下的(8-2=6bit内。
x.c=4;  二进制1005bit,00100存哪?新开一个字节,还是整体利用?

问题:
1)大小端决定字节的顺序,那字节的内部呢?(精细不到这种程度),不知道是先从一个字节内的低bit位还是高bit位开始存。
2)如果字节空间不够是继续使用剩下的,还是重新开一个?

c. 应用场景

Ipv4报头格式,没想到可以从C语言的角度看报头,其实就是为每个标志位预先分配了相应bit数的地址。

3.枚举

可以简单的理解为,配置常量。把整型放入枚举类型的符号里(不赋值,则默认从0开始加1)。

与“#define XXXX 值”的区别

1)枚举是个类型,define没有类型。
2)枚举把常量配置放在一起,好看,可读性好。
3)#define会预编译,导致调试不便。

4.联合体(共用体)

成员变量共用一块空间(首地址相同),这就要注意,不能改一个成员而影响了另一个。
功能:联合体内部查看。(int四个字节,我用char查看你的第一个字节。)
对齐:对齐最大对齐数的整数倍。

你可能感兴趣的:(c语言,学习,开发语言)