C语言学习笔记 _内存对齐大小端共用体等
C语言学习笔记 _内存对齐大小端共用体等
offsetof宏
offset宏返回的是member元素相对于整个结构体变量的首地址的偏移量,类型是int:
#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
这个宏的原理是,在地址0处虚拟此结构体,然后用地址0的结构体指针获得member元素的地址,那么此地址的数值相当于是偏移量,因为从0出发的地址,偏移量就是其本身;
container_of宏
container_of宏返回指向整个结构体变量的指针,类型是(type *);
ptr是指向结构体元素member的指针,type是结构体类型,member是结构体中一个元素;
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
此宏通过获取member的数据类型,和其地址ptr,定义与member相同类型的变量__mptr,注意代码中((type *)0)->member)只是为了定义一个结构体以获得member的变量类型,(之所以要这么复杂定义这个指针,是为了不改变ptr这个源指针)。最后利用此地址减去偏移量就可以得到结构体的地址了;
通过此宏,可以从一个元素的指针的指针,得到整个结构体变量的指针,结合offset可以得到所有元素的指针;
typeof关键字的作用是:得到变量的数据类型;
共用体union
共用体方式的使用方法和结构体基本一致;但是含义完全不同;
共用体就是对同一块内存中存储的二进制不同的理解方式;也就是申明同一块内存的不同数据类型;
sizeof共用体,得到的是各元素中占用内存最大的元素的大小;
共用体方法可以用指针加强制类型转换来替代,如下所示:
union student{
int a;
float b;
};
// 共用体方式
union test t1;
t1.a = 1123477881;
printf("value = %f.\n", t1.b);
// 指针方式
int a = 1123477881;
printf("point mode: %f.\n", *(float *)&a);
大小端模式
这是两种数据在内存种的存储方式:
大端模式:数据高位存放于低地址,低位存放于高地址;
小端模式:数据高位存放于高地址,低位存放于低地址;
当不确定大小端模式的时候,通过union来判断大小端模式:
union un {
int a;
char b;
};
// 判断函数
int check(void) {
union un u1;
u1.a = 1;
return u1.b;
}
// 输出1则为小端模式,输出0则为大端模式
printf("mode is %d.\n", check());
通过union方式判断大小端模式的依据是,int类型占用四字节,数据为00 00 00 01:
大端模式下存放方式为:00 00 00 01;小端模式下存放的方式为:01 00 00 00;
那么当把这段内存按照char读取的时候只会读取低地址的一个字节,于是大端模式下为0,小端模式为1;
另外,位与运算、移位、强制类型转换不能用于检测大小端,因为编译器对其做了封装。
枚举
enum week {
SUM,
MON,
TUE,
};
enum value {
TRUE = 12,
FALSE = 13,
};
枚举相当于用符号代替数字,作用于全局,可直接使用。
如果只声明符号,默认从0开始,也可以声明符号与数字。