linux内核 sin头文件,c 笔记 6

位字段

:【专用于结构 体,结构体成员的类型必须是:int || unsigned int有时侯,结构体成员表示的数据很小,就用几个位来表示】。

例如

struct data1

{

unsigned a : 1; // 1就是一个bit,范围:0~1

int : 31; // 无名字段,不可访问,只是占位

unsigned b : 2; // 2就是er个bit,范围:0~3

unsigned c : 32; // 32个bit 范围:ffffffff~0

int : 0; // 0字段,不可访问,只是占位 整个字剩下的位,全部写0

}s1;

注意

1 位字段:下一个字段不够在剩余的bit存放时,必须另起一个字。字段不能跨字 所以 bit的范围最大就是32。

2 超出字段表示的数据范围,结果不可预期

3 字段不可取地址

对齐

结构体内成员对齐规则:

1、我们的结构体变量本身就是在4字节对齐的位置,编译器帮我们做的事。

2、第一个成员,就从结构体开始的地址处,存放。这个元素,具体占多少字节,由紧挨着下个元素决定。

3、整个成员变自身都对齐 了,还没有结束。

4、整个结构体还要是默认字节对齐的最小整数倍。

5,结构体默认的字节对齐:成员变量最大的那个类型所占字节

例如

【1】

typedef struct data

{

int a; // 4

char b; // 1 + 1(填充)

short c; // 2 最后整个结构体自身还要对齐

double d; //8

}D;

【2】 //16

struct da

{

int a;

short b;

int c;

double e;

}; // 16

struct data

{

char a; //1+1

short b; //2

int c; // 4

double e; // 8

struct da s; // 16

char ch;

}s ;

//1、不会因为有结构体成员,而影响你的基本类型,决定默认对齐

//2、里面的结构体对齐方式,已经在外面决定了(遍历整个完整结构体)

对齐指令

1 形式 #/*#pragma pack(n) (1、2、4、8、.....)

...........

#pragma pack()

【这两个配合使用,表示一个区间,只有这个区间内的结构体享受这个待遇。设置 n 就是n对齐。设置为1,就是不对齐】

2作用

1、充分利用内存空间,牺牲了速度,降低了访问效率。

2、提高效率、性能,牺牲了内存空间。

3 总结 :你指定的对齐方式和结构体自身默认对齐方式,俩者取最小的。

例如

#pragma pack(2)

struct data // 16

{

int a;

char b;

double c;

}s;

#pragma pack()

printf("sizeof(s) = %d.\n", sizeof(s)); // 1字节对齐 13

printf("sizeof(s) = %d.\n", sizeof(s)); // 2字节对齐 14

结构体成员变量的问题

struct data

{

int a; // 4 + 4(padding)

// int b;

struct data *p_next; //64bit机器指针永远永远占8字节

}S;

struct data1

{

int a;

// struct data1 s; // 1、【此时结构体类型(定义)不完整 2、C语言不准】

}s;

linux内核里的两个宏

1

#define off_set_of(type, member) ((long)&(((type *)0)->member))

意义:计算结构体内元素的偏移量

分析:1、(type *)0指向结构体零地址

2、((type *)0)->member得到了结构体某个成元变量名

3、给这成员变量名,取地址(相对于零地址),此时&(((type *)0)->member)表示是指针类型 \

4、强制类型转换成(long)。

例如

int off = off_set_of(struct data, c);

printf("off = %d.\n", off);

2

#define container_of(ptr, type, member) \

({typeof(((type )0)->member)_mptr = ptr; \

(type )((char)_mptr-off_set_of(type, member));})

意义:ptr是结构体里成员的指针,通过调用这个宏计算出结构体的首地址

分析: 1、得到结构体成员变量的类型

2、指针赋值(得到真实成员变量的地址值)

3、减去偏移量得到一个数字,该数字和结构体本身首地址在数值上一样

4、最后强制类型转换为结构体指针类型

例如

struct data *p = container_of(p_e, struct data, e);

struct data *p = container_of(&s.e, struct data, e);

printf("p = %p.\n", p);

网络结构体

头文件 #include

#include

#include

#include

#include

#include

#include

【这些头文件包括】

typedef uint32_t in_addr_t;

typedef uint16_t in_port_t; // 16的无符号short类型

【第一个结构体】

struct in_addr

{

in_addr_t sin_addr;

};

/Structure describing an Internet socket address./

【第二个结构体】

struct sockaddr_in

{

__SOCKADDRCOMMON (sin); /AF_INET IPv4 Internet protocols 指定网络地址类型/

in_port_t sin_port; /Port number. 端口号 16位无符号short/

struct in_addr sin_addr; /Internet address. 具体的网址32位无符号int/

}

【首先宏定义】

#define PORT 0x1234

#define ADDR "19.16.1.22" //把本地ip地址转换成网络字节序地址

演示网络结构体赋值

【第一种 】【输出型函数】

void set_net_struct(struct sockaddr_in *p)【输出型函数】

{

p->sin_family = AF_INET;

p->sin_port = htons(PORT);

p->sin_addr.s_addr = inet_addr(ADDR);

}

int main(void)

{

struct sockaddr_in s; //赋值

set_net_struct(&s); //出入头文件中结构体的地址

} printf("网络字节序地址:0x%x.\n", s.sin_addr.s_addr);

【第二种】

int main(void)

{

1、struct sockaddr_in定义这种类型的结构体变量

struct sockaddr_in s;

2、填充你这个结构体各成员

s.sin_family = AFINET;

s.sin = AF_INET; (错误)

//但是已经错了,你的发送数据包,肯定找不到对方。

//传送过去的IP/PORT都是网络字节序,大端模式:低位(字节)要放到高地址。

s.sin_port = htons(PORT);

printf("s.sin_port = 0x%x.\n", s.sin_port);

s.sin_addr.s_addr = inet_addr(ADDR);

//0x16011013

printf("网络字节序地址:0x%x.\n", s.sin_addr.s_addr);

#endif

return 0;

}

柔性数组

:【1 是在结构体里,有一个数组,必须是结构体最后的一个元素,而且由特定形式[]或[0];

2 整体的结构体至少有两个成员变量】

不好之处:1、p(字符串)压根就没用,2、每次要用字符串时,很麻烦(char *)(p+1)。。

typedef struct data

{

int a;

char *p; // 结构体里存储的字符串, 和你结构体时分离的。

}D;

类型

typedef struct

{

int len;

int arr[];

}S;

枚举

:【里面成员必须大写】

定义常量符号,就是宏定义常数的集合体

比如:四季,星期,意义相关的常数

状态机:1、根据当前状态,这个周期结束,就成了下一个状态。

2、根据你的当前状态,还和你的输入有关。比如:fpga, GUI(用户图形交互界面)

例题

密码锁

typedef enum STATE

{

STATE1,

STATE2,

STATE3,

STATE4,

STATE5,

STATE6,

STATE7,

}S;

int main(void)

{

int num = 0;

//1、密码锁初始状态

S current_state = STATE1;

// 输入密码,进行解锁

printf("输入一个密码数字:");

while (1)

{

scanf("%d", &num);

printf("num = %d.\n", num);

//解锁子开始

switch (current_state)

{

case STATE1:

if (num == 9)

{

current_state = STATE2; // 用户每输对一次,进入下一状态

}

else

{

current_state = STATE1;

}

break;

case STATE2:

if (num == 5)

{

current_state = STATE3; // 用户每输对一次,进入下一状态

}

else

{

current_state = STATE1;

}

break;

case STATE3:

if (num == 2)

{

current_state = STATE4; // 用户每输对一次,进入下一状态

}

else

{

current_state = STATE1;

}

break;

case STATE4:

if (num == 7)

{

current_state = STATE5; // 用户每输对一次,进入下一状态

}

else

{

current_state = STATE1;

}

break;

default:

current_state = STATE1;

break;

}

if (current_state == STATE5)

{

printf("开了锁,请进!.\n");

//break

return 0;

}

if (current_state == STATE1)

{

printf("初始状态.\n");

}

}

/*

E e = EAST;

printf("e = %d.\n", e);

e = xq;

printf("e = %d.\n", e);

*/

return 0;

}

C++里面面向对象,多态

1 结构体各成员默认是public

2 class在C++里,是一个类,所有成员和方法(函数)是si(private)有的,只能在类里进行访问

3 struct里面不能包含函数,但是可以包含函数指针

4 不能有函数

struct data

{

int a;

int b;

p_func p;

//不能有函数

// int add(int a, int b);

}s;

//填充结构体

void set_func(struct data p)

{

p->a = 2;

p->b = 3;

// p->p = add;

p->p = mul_a_b;

}

//业务函数

int cnt_func(struct datap_str)

{

return p_str->p(p_str->a, p_str->b);

}

int main(void)

{

set_func(&s);

int ret = cnt_func(&s);

printf("ret = %d.\n", ret);

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值