结构体
1.字节对齐
知识点:
对齐规则:1、我们的结构体变量在4字节对齐的位置。
2、第一个成员,从结构体开始的地址处存放。具体占多少字节,由紧挨着下个元素决定。
3、整个结构体是默认字节对齐的最小整数倍。
//结构体默认的字节对齐:成员变量最大的那个类型所占字节
举例:
#include<stdio.h>
struct data
{
char a;//填充1
short b;//填充4
double c;
}A;
sizeof(A)=16 byte
注意:
结构体不允许此类定义
struct data
{
int a;
struct data s; // 此时结构体类型(定义)不完整
}s;
2.结构体嵌套
知识点:
1、不会因为有结构体成员,而影响你的基本类型,只决定默认对齐方式
2、里面的结构体对齐方式,已经在外面决定了(遍历整个完整结构体)
举例:
struct data1
{
int a;
short b;
int c;
double e;
};//24
struct data
{
char a;//2
short b;//2
int c;//4
struct data1 s;//24
char ch;//8
}//40
3.对齐指令
知识点:
#pragma pack(n) (1、2、4、8、…..)
#pragma pack()
表示一个区间,区间内的结构体有此设置
指定的对齐方式和结构体自身默认对齐方式取最小的。
作用:
1、充分利用内存空间,牺牲了速度,降低了访问效率。
2、提高效率、性能,牺牲了内存空间。
举例:
#include <stdio.h>
#pragma pack(2)
struct
{
int a;
char b;
}A;
#pragma pack()
sizeof(A)=6 byte
4.位字段
知识点:
1.专用于结构体,结构体成员的类型必须是:int || unsigned int
2.字段不可取地址
3.0字段,不可访问,只是占位整个字中剩下的位,全部写0
4.无名字段,不可访问,只是占位
5.字(word)=32bit
6.下一个字段不够在剩余的字存放时,必须另起一个字。字段不能跨字。
7.超出字段表示的数据范围,结果不可预期
8.若最后一个字没有填满则也将填满后返回
举例:
//写法
struct data
{
unsigned a : 1; // 1就是一个bit,范围:0~1
int :0; // 0字段,不可访问,只是占位 整个字剩下的位,全部写0
unsigned b : 2; // 2就是两个bit,范围:0~3
int:31; // 无名字段,不可访问,只是占位
}A;
sizeof(A)=3 word=12 byte
注意:
struct
{
int a:1;//此时a只有一位且仅为符号位,取值范围为(-1~0)
};
5.网络结构体
知识点:
头文件路径:/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)];
};
利用以上内容定义sockaddr_in结构体并赋值
#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;
}
6.结构体与函数
知识点:
结构体中不能调用函数,需要声明函数指针
实现:
#include <stdio.h>
typedef int (*p_func)(int a,int b);//重命名函数类型为函数指针
int add(int a,int b)//函数本体,实现具体功能
{
return a+b;
}
struct data
{
int a;
int b;
p_func p;//函数指针
}s;
void set_func (struct data *s)//结构体赋值
{
s->a=1;
s->b=2;
s->p=add;
}
int ret_func (struct data *s)//函数使用
{
return s->p(s->a,s->b);
}
int main(void)
{
struct data s;
set_func(&s);
int ret=ret_func(&s);
printf("%d\n",ret);
return 0;
}
7.柔性数组
知识点
标志是结构体的最后一个成员是一个没有定义大小的数组
需要malloc动态申请数组大小后使用
实现
1.int型数组
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int len;
int arr[];
}S;
S* create_soft_arr(int len)
{
S* p=(S*)malloc(sizeof(S)+sizeof(int)*len);
if(NULL==p)
printf("malloc error");
p->len=len;
return p;
}
void set_arr(S* p)
{
int i=0;
for(i=0;i<(p->len);i++)
{
if(i<=1)
p->arr[i]=1;
else if(i>=2)
p->arr[i]=p->arr[i-1]+p->arr[i-2];
}
}
void show_arr(S* p)
{
int i=0;
for(i=0;i<(p->len);i++)
{
printf("%d ",p->arr[i]);
}
}
int main(void)
{
S* p = create_soft_arr(5);
set_arr(p);
show_arr(p);
return 0;
}
2.char型数组
#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;
}
宏
举例
1.
__FILE__:所在文件
__LINE__:所在行数
2.
#define handle_error(msg) (do{perror(msg); exit(EXIT_FAILURE);}while(0))
解释:
perror:检查系统错误的宏.一旦发生了,系统错误就会产生一个错误数字(errno),对应相应的错误字符串。
EXIT_SUCCESS 和 EXIT_FAILURE:C 标准定义了两个值,可以作为exit()的参数,来分别指示是否为成功退出。
exit():传递给的是父进程,或者shell终端
3.linux内核里的两个宏:在驱动应用中很广泛
off_set_of(type, member)计算结构体内元素的偏移量
containe_of(ptr, type, member)结构体的首地址,需传入该结构体的成员地址
原理:
#define off_set_of(type, member) ((long)&((type*)0->member))
将0转换为结构体类型的指针,再指向其成员,将地址转换为数值接收即为偏移量
#define container_of(ptr, type, member) ({typeof ((type*)0->member) *mystr = ptr ; (type *)((long)mystr-off_set_of(type,member));})
将0转换为结构体类型指针,再指向其成员,调用typeof函数得到成员类型并申请一个该类型的指针,赋值为传入的成员地址str;该地址减去偏移量即结构体的首地址
补充:
typeof(),得到参数的类型。参数可以是变量名或者表达式。
int *p, a;
//变量名作参数
typeof(p) p_a = &a;
//表达式作参数
typeof(*p_a) b = 23;
枚举
知识点:
枚举:定义常量符号,就是宏定义常数的集合体。如四季,星期,意义相关的常数
举例:
实现密码锁,循环输入至出现正确密码
#include <stdio.h>
typedef enum//书写格式
{
STATE1,//以逗号结尾
STATE2,
STATE3,
STATE4,
}S;
int main(void)
{
S c_state = STATE1;//声明一个变量的格式,以枚举值赋值
printf("Input key:");
int num=0;
while(1)
{
scanf("%d",&num);
switch(c_state)
{
case STATE1:
if(num == 2)
c_state=STATE2;
else
c_state=STATE1;
break;
case STATE2:
if(num == 2)
c_state=STATE3;
else
c_state=STATE1;
break;
case STATE3:
if(num == 1)
c_state=STATE4;
else
c_state=STATE1;
break;
default:
c_state=STATE1;
break;
}
if(c_state==STATE4)
{
printf("successful\n");
return 0;
}
}
return 0;
}
本文详细介绍了C语言中的结构体,包括字节对齐规则、结构体嵌套、对齐指令#pragma pack的应用、位字段的使用限制、网络结构体的定义以及在函数中的应用。同时,还探讨了宏的常见用法,如__FILE__、__LINE__等,并提到了枚举在定义常量符号中的作用。

2178

被折叠的 条评论
为什么被折叠?



