c语言基础(八)
2017-12-26 18:01
127 查看
字节对齐
结构体内成员对齐规则:1、我们的结构体变量本身就是在4字节对齐的位置,编译器帮我们做的事。
2、第一个成员,就从结构体开始的地址处,存放。这个元素,具体占多少字节,由紧挨着下个元素决定。
3、整个成员变量自身都对齐 了,还没有结束。
4、整个结构体还要是默认字节对齐的最小整数倍。
结构体默认的字节对齐:成员变量最大的那个类型所占字节
#include<stdio.h> typedef struct data { int a; // 4 char b; // 1 + 1(填充) short c; // 2 最后整个结构体自身还要对齐 }D; int main(void) { printf("sizeof(D)=%d.\n",sizeof(D)); return 0; } 结果为8byte
注意:
struct data { int a; struct data s; // 1.此时结构体类型(定义)不完整 2.C语言不允许 }s;
int main(void) { unsigned short a = 0x1234; unsigned char * p1 = (unsigned char *)&a, i = 8; //*p1 << i,就产生了临时变量,内存中你不知道地址,但是有一个默认类型(int) printf("sizeof(*p1 << i) = %d.\n", sizeof(*p1 << i)); printf("0x%x.\n", *p1 <<= i); // printf("%d.\n", a *= 2); printf("0x%x.\n", *(p1+1)); } 结果如下:sizeof(*p1 << i)=4 0x0 0x12
#include<stdio.h> struct data { int a; // 4 + 4(padding) struct data *p_next; //64bit机器指针永远永远占8字节 }S; int main(void) { printf("sizeof(S)=%d.\n",sizeof(S)); return 0; } 结果为16byte
结构体的嵌套
#include<stdio.h> struct data1 { int a; short b; int c; double e; };//24 typedef struct data { char a;//2 short b;//2 int c;//4 struct data1 s;//24 char ch;//8 }S; int main(void) { printf("sizeof(S)=%d.\n",sizeof(S)); return 0; } 结果为40
字段对齐
位字段:专用于结构体,结构体成员的类型必须是:int || unsigned int有时侯,结构体成员表示的数据很小,就用几个位来表示。
0字段,不可访问,只是占位整个字中剩下的位,全部写0
无名字段,不可访问,只是占位
字(word)=32bit
下一个字段不够在剩余的字存放时,必须另起一个字。字段不能跨字。
超出字段表示的数据范围,结果不可预期
若最后一个字没有填满则也将填满后返回
字段不可取地址
#include <stdio.h> struct data1 { unsigned a : 1; // 1就是一个bit,范围:0~1 int : 31; // 无名字段,不可访问,只是占位 unsigned b : 2; // 2就是2个bit,范围:0~3 unsigned c : 2; // 28位 }s1; int main(void) { printf("szieof(s1) = %d.\n", sizeof(s1)); return 0; } 结果为8byte,同时也是2word
特别的是:
struct { int a:1;//此时a只有一位且仅为符号位,取值范围为(-1~0) };
对齐指令
#pragma< 4000 /span> pack(n) (1、2、4、8、.....) #pragma pack()
这两个配合使用,表示一个区间,只有这个区间内的结构体享受这个待遇。
设置 对齐。
如果将n设置为1,就是不对齐
1、充分利用内存空间,牺牲了速度,降低了访问效率。
2、提高效率、性能,牺牲了内存空间。
总结:你指定的对齐方式和结构体自身默认对齐方式,俩者取最小的。
#include <stdio.h> #include <stdlib.h> #pragma pack(2) struct data // 16 { int a; char b; double c; }s; struct data1 { char ch; }s1; #pragma pack()
检查系统错误的宏
一旦发生了,系统错误就会产生一个错误数字(errno),对应相应的错误字符串。C标准定义了两个值 EXIT_SUCCESS 和 EXIT_FAILURE,可以作为exit()的参数,来分别指示是否为成功退出。
exit(参数)传递给的是父进程,或者shell终端
#define handle_error(msg) do{perror(msg); exit(EXIT_FAILURE);}while(0)
Linux内置宏
linux内核里的两个宏:在驱动应用中很广泛。off_set_of(type, member)计算结构体内元素的偏移量
containe_of(ptr, type, member),ptr是结构体里成员的指针,通过调用这个宏计算出结构体的首地址.包含两句代码(表达式),必须要加{}.
这两个宏:内核双链表。
分析: #define off_set_of(type, member) ((long)&(((type *)0)->member)) 1、(type *)0指向结构体零地址 2、((type *)0)->member得到了结构体某个成元变量名 3、给这成员变量名,取地址(相对于零地址),此时&(((type *)0)->member)表示是指针类型 4、强制类型转换成(long) #define container_of(ptr, type, member) ({typeof(((type *)0)->member) *_mptr = ptr;(type *)((char *)_mptr-off_set_of(type, member));}) 1、得到结构体成员变量的类型 2、指针赋值(得到真实成员变量的地址值) 3、减去偏移量得到一个数字,该数字和结构体本身首地址在数值上一样 4、最后强制类型转换为结构体指针类型
举个栗子:
#include <stdio.h> #define off_set_of(type, member) ((long)&(((type *)0)->member)) #define container_of(ptr, type, member) ({typeof(((type *)0)->member) *_mptr = ptr;(type *)((char *)_mptr-off_set_of(type, member));}) struct da { int a; short b; int c; double e; }; // 16 struct data { char a; short b; int c; // 8 struct da s; // 16 char ch; }s = {1, 3, 10, 3.14, 1.41}; //1、不会因为有结构体成员,而影响你的基本类型,决定默认对齐 //2、里面的结构体对齐方式,已经在外面决定了(遍历整个完整结构体) int main(void) { printf("sizeof(s) = %d.\n", sizeof(s)); //结构体自身的首地址 printf("&s = %p.\n", &s); struct da *p = container_of(&s.s.b, struct da, b); printf("p = %p.\n", p); printf("&s.s = %p.\n", &s.s); return 0; } p->a == (struct data *)0->a; /* //让你明白强制转换0地址 struct data *p; unsigned long a = 0; p = (struct data *)a; p->a == (struct data *)0->a; */
关于typeof
typeof(),()里面的参数可以是变量名或者表达式。typeof(int) p
int *p, a; typeof(p) p_a = &a;//将p_a的类型转换为p的类型,即指针类型
相关文章推荐
- 一位牛人归纳的JavaScript 语言基础知识点图示(下)
- asp.net从入门到精通看书笔记.一些c#语言基础
- java语言基础(8)——数据类型转换(默认转换和强制转换)
- Call指令和Ret指令讲解04 - 零基础入门学习汇编语言51
- HTML语言基础
- 嵌入式linux工程师面试题目C语言基础部分 (2
- go 语言基础
- Call指令和Ret指令讲解06 - 零基础入门学习汇编语言53
- go语言学习基础
- C++语言基础 例程 案例:Time类的设计
- 你所熟知的javascript?从基础原理开始认识JS语言
- 黑马程序员-OC语言基础:面向对象语法 二
- 从零开始系列-R语言基础学习笔记之二 数据结构(一)
- 【C语言基础一百题9】66-70题排序和查找方式
- C语言基础2
- 10.java语言基础-字符类型(char)
- Apple Swift语言基础入门 —— Swift概览5
- SQL语言基础
- java语言基础-控制循环语句-break- continue-return的区别
- 黑马程序员-C语言基础知识-运算符与表达式