C语言知识小结(六)


结构体



字节对齐


结构体内成员对齐规则:

1、我们的结构体变量本身就是在4字节对齐的位置,编译器帮我们>做的事。
2、第一个成员,就从结构体开始的地址处,存放。这个元素,具体占多少字节,由紧挨着>下个元素决定。
3、整个成员变量自身都对齐 了,还没有结束。
4、整个结构体还要是默认字节对齐的最小整数倍。

typedef struct data (共16字节)
{
int a; // 4
char b; // 1 + 1(填充)
short c; // 2 最后整个结构体自身还要对齐
// double d; //8
}D;



对齐指令:


#pragma pack(n) (1、2、4、8、…..)
#pragma pack()
这两个配合使用,表示一个区间,只有这个区间内的结构体享受这个待遇。
设置为1,就是不对齐


作用:

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

#pragma pack(2)
struct data // 6
{
int a; // 4
char b; // 1+1
}s;
#pragma pack()



位字段


位字段:
1,专用于结构体,结构体成员的类型必须是:int || unsigned int
2,有时侯,结构体成员表示的数据很小,就用几个位来表示。
3,下一个字段不够在剩余的bit存放时,必须另起一个字。字段不能跨字。
4.无名字段,不可访问,只是占位
5.字(word)=32bit
6.0字段,不可访问,只是占位整个字中剩下的位,全部写0
7.超出字段表示的数据范围,结果不可预期

struct data
{
unsigned a : 1; // 1就是一个bit,范围:0~1
unsigned b : 2; // 2就是er个bit,范围:0~3
unsigned c : 2; // 28位
}s, *p = &s;
//word 32位 就是一个int
struct data1
{
unsigned a : 1; // 1就是一个bit,范围:0~1
int : 31; // 无名字段,不可访问,只是占位
unsigned b : 2; // 2就是er个bit,范围:0~3
unsigned c : 2; // 28位
}s1;

struct data2
{
unsigned a : 1; // 1就是一个bit,范围:0~1
int : 0; // 0字段,不可访问,只是占位 整个字剩下的位,全部写0
unsigned b : 30; // 2就是er个bit,范围:0~3
int : 0;
unsigned c : 2; // 28位
}s2;



网络结构体:


vim /usr/include/netinet/in.h 打开网络配置的头文件内容


/* Internet address. */
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t; // 16的无符号short类型
struct in_addr
{
in_addr_t s_addr;
};

/* Structure describing an Internet socket address. */
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_); /* AF_INET IPv4 Internet protocols 指定网络地址类型*/
in_port_t sin_port; /* Port number. 端口号 16位无符号short */
struct in_addr sin_addr; /* Internet address. 具体的网址32位无符号int*/

/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};


网络结构体的使用:


#include <stdio.h>
#include <features.h>
#include <stdint.h>
#include <sys/socket.h>
#include <bits/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 1234
#define ADDR "172.25.254.3"

void set_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_struct(&s);

return 0;
}






                  

__FILE__:所在文件
__LINE__:所在行数



查错的宏:


#define handle_error(msg) (do{perror(msg); exit(EXIT_FAILURE);}while(0))

解释:
perror:检查系统错误的宏.一旦发生了,系统错误就会产生一个错误数字(errno),对应相应的错误字符串。
EXIT_SUCCESS 和 EXIT_FAILURE:C 标准定义了两个值,可以作为exit()的参数,来分别指示是否为成功退出。
exit():传递给的是父进程,或者shell终端



linux内核里的两个宏:在驱动应用中很广泛。

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


//计算结构体内元素的偏移量off_set_of(type, 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));})


//计算出结构体的首地址containe_of(ptr, type, member)需传入该结构体的成员地址.


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

2、指针赋值(得到真实成员变量的地址值)
3、减去偏移量得到一个数字,该数字和结构体本身首地址在数值上一样
4、最后强制类型转换为结构体指针类型



     枚举法



枚举:定义常量符号,就是宏定义常数的集合体
比如:四季,星期,意义相关的常数
状态机:1、根据当前状态,这个周期结束,就成了下一个状态。
2、根据你的当前状态,还和你的输入有关。比如:fpga, GUI(用户图形交互界面)密码锁

typedef enum fangxiang //标识符
{ //成员必须大写
EAST,
WEST = 99,
SAUTH,
NORTH = 100,
xq,
}E;
//定义状态机的所有状态集
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");
return 0;
}
if (current_state == STATE1)
{
printf("初始状态.\n");
}
}

return 0;
}





      柔性数组



柔性数组:是在结构体里,有一个数组,必须是结构体最后的一个元素,而且由特定形式[]或[0];
整体的结构体至少有两个成员变量。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct
{
int len;
char arr[]; //不占空间,只是一个符号(常量地址)
}S;

//生成柔性数组
int main(void)
{
char a[]="abcd";
S* p=(S*)malloc(sizeof(S)+sizeof(a));
strcpy(p->arr,a);

printf("%s",p->arr);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值