编译连接过程
union 联合体
在数据解析中的应用
typedef union {
uint8_t buffer [PACKET_SIZE];
struct {
uint8_t size;
uint8_t CMD;
uint8_t payload[PAYLOAD_SIZE];
uint8_t crc;
} fields;
} PACKET_t;
- // 函数调用方法:packet_builder(packet.buffer,new_data)
- // 将新数据存到 buffer 的时候,还需要一些额外的操作
- // 比如应该将 size 存放 buffer[0]中
- // 将 cmd 存放到 buffer[1] 中,依次类推
- void packet_builder(uint8_t *buffer,uint8_t data)
- {
- static uint8_t received_bytes = 0;
- buffer[received_bytes++] = data;
- }
- void packet_handler(PACKET_t *packet)
- {
- if (packet->fields.size > TOO_BIG)
- {
- //错误
- }
- if (packet->fields.cmd == CMD)
- {
- //处理对应的数据
- }
- }
要理解这个数据解析过程,需要用到 union 中的成员存放在同一个地址这个特性,buffer[PACKET_SIZE]中的元素与 fields 中的元素是一一对应的,用一张图来表示就很清楚
往 buffer 里写了数据,直接从 fileds 里面读出来就可以了。
链表
https://www.cnblogs.com/skywang12345/p/3562146.html
#define offset(type, member) (size_t)(&((type *)0->member))
#define container_of(ptr, type, member) (type *)((char *)ptr - offset(type, member))
struct list_head {
struct list_head *pre;
struct list_head *next;
};
#ifndef _LIST_HEAD_H
#define _LIST_HEAD_H
// 双向链表节点
struct list_head {
struct list_head *next, *prev;
};
// 初始化节点:设置name节点的前继节点和后继节点都是指向name本身。
#define LIST_HEAD_INIT(name) { &(name), &(name) }
// 定义表头(节点):新建双向链表表头name,并设置name的前继节点和后继节点都是指向name本身。
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
// 初始化节点:将list节点的前继节点和后继节点都是指向list本身。
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
// 添加节点:将new插入到prev和next之间。
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
// 添加new节点:将new添加到head之后,是new称为head的后继节点。
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
// 添加new节点:将new添加到head之前,即将new添加到双链表的末尾。
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
// 从双链表中删除entry节点。
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
// 从双链表中删除entry节点。
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
// 从双链表中删除entry节点。
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
// 从双链表中删除entry节点,并将entry节点的前继节点和后继节点都指向entry本身。
static inline void list_del_init(struct list_head *entry)
{
__list_del_entry(entry);
INIT_LIST_HEAD(entry);
}
// 用new节点取代old节点
static inline void list_replace(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
// 双链表是否为空
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
// 获取"MEMBER成员"在"结构体TYPE"中的位置偏移
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
// 根据"结构体(type)变量"中的"域成员变量(member)的指针(ptr)"来获取指向整个结构体变量的指针
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
// 遍历双向链表
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#endif
//双向链表测试代码(test.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
struct person
{
int age;
char name[20];
struct list_head list;
};
void main(int argc, char* argv[])
{
struct person *pperson;
struct person person_head;
struct list_head *pos, *next;
int i;
// 初始化双链表的表头
INIT_LIST_HEAD(&person_head.list);
// 添加节点
for (i=0; i<5; i++)
{
pperson = (struct person*)malloc(sizeof(struct person));
pperson->age = (i+1)*10;
sprintf(pperson->name, "%d", i+1);
// 将节点链接到链表的末尾
// 如果想把节点链接到链表的表头后面,则使用 list_add
list_add_tail(&(pperson->list), &(person_head.list));
}
// 遍历链表
printf("==== 1st iterator d-link ====\n");
list_for_each(pos, &person_head.list)
{
pperson = list_entry(pos, struct person, list);
printf("name:%-2s, age:%d\n", pperson->name, pperson->age);
}
// 删除节点age为20的节点
printf("==== delete node(age:20) ====\n");
list_for_each_safe(pos, next, &person_head.list)
{
pperson = list_entry(pos, struct person, list);
if(pperson->age == 20)
{
list_del_init(pos);
free(pperson);
}
}
// 再次遍历链表
printf("==== 2nd iterator d-link ====\n");
list_for_each(pos, &person_head.list)
{
pperson = list_entry(pos, struct person, list);
printf("name:%-2s, age:%d\n", pperson->name, pperson->age);
}
// 释放资源
list_for_each_safe(pos, next, &person_head.list)
{
pperson = list_entry(pos, struct person, list);
list_del_init(pos);
free(pperson);
}
}
链表节点定义
首节点:存放第一个有效数据
尾节点:存放最后一个有效数据
头节点:头节点和首节点的数据类型一致,但并不存放有效数据
头节点是首节点前面的那个节点
设置头结点的目的是为了方便对链表操作
头指针:存放头节点的地址
#include<stdio.h>
#include<malloc.h>
#include<stdbool.h>
/**
**链表节点的定义
*/
typedef struct Node{
int data; //数据域
struct Node * PNext;//指针域,存放下一个节点的地址
} Node ,*PNode ;
/**
**创建链表
*/
PNode create_list()
{
int len,i;
printf("请输入链表的长度:len=\n");
scanf("%d",&len);
PNode PHead=malloc(sizeof(Node));
PHead->PNext=NULL;
PNode PTail=PHead;//PTail是永远指向尾节点的指针
for(i=0;i<len;i++)
{
int val;
printf("请输入第 %d 个元素的值:", i+1);
scanf("%d",&val);
PNode PNew=malloc(sizeof(Node));
PNew->data=val;
PNew->PNext=NULL;
PTail->PNext=PNew;
PTail=PNew;
}
return PHead;
}
/**
**对链表进行遍历
*/
void traverse(PNode pHead)
{
PNode p=pHead->PNext;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->PNext;
}
printf("\n");
}
/**
*判断链表是否为空
*/
bool isempty(PNode pHead)
{
if(NULL==pHead->PNext)
{
return true;
}else{
return false;
}
}
/**
**获取链表的长度
*/
int list_num (PNode pHead)
{
int num=0;
PNode p=pHead->PNext;
while(p!=NULL)
{
num++;
p=p->PNext;
}
return num;
}
/**
*向链表中插入元素
*/
bool insert_list(PNode pHead,int val ,int pos){
//需要找到第pos个位置,并且需要判断这个位置pos是否合法
//i是p所指节点的位置,所以从一开始,为什么要pos-
//1呢,因为用的是while 当i=pos-1时跳出循环
int i=0;
PNode p=pHead;
while(NULL!=p&&i<pos-1)
{
i++;
p=p->PNext;
}
//如果插入位置过大,那么P=NULL,
//如果插入的位置是0或者负数,那么i>pos-1
if(i>pos-1||NULL==p)
{
printf("插入位置不合法\n");
return false;
}
PNode PNew=malloc(sizeof(PNode));
PNew->data=val;
PNode temp=p->PNext;
p->PNext=PNew;
PNew->PNext=temp;
return true;
}
/**
**在链表中删除节点
*/
delete (PNode PHead,int pos , int * pval)
{
int i=0;
PNode p=PHead;
//我们要删除p后面的节点,所以p不能指向最后一个节点
p->next!=NULL
while(p->PNext!=NULL&&i<pos-1){
p=p->PNext;
i++;
}
if(i>pos-1||p->PNext==NULL)
{
printf("删除位置不合法\n");
return false;
}
PNode temp=p->PNext;
p->PNext=temp->PNext;
free(temp);
}
int main()
{
PNode PHead = create_list();
if(isempty(PHead))
printf("链表为空\n");
printf("链表的长度为:%d\n",list_num(PHead));
traverse(PHead);
//insert_list(PHead,55,1);
int val;
delete(PHead,6,&val);
traverse(PHead);
return 0;
}
===============================================
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct name {
char *name;
struct name *pre;
struct name *next;
} t_name, *pt_name;
static pt_name g_pt_name_head = NULL;
int32_t add_name(pt_name pt_new)
{
pt_name pt_cur;
if (!g_pt_name_head){
g_pt_name_head = pt_new;
} else {
pt_cur = g_pt_name_head;
while (pt_cur->next){
pt_cur = pt_cur->next;
}
pt_cur->next = pt_new;
pt_new->pre = pt_cur;
}
return 0;
}
int32_t add_one_name(void)
{
pt_name pt_new;
char *str;
char name[32];
printf("enter the name:");
scanf("%s", name);
str = malloc(strlen(name)+1);
strcpy(str,name);
pt_new = malloc(sizeof(t_name));
pt_new->name = str;
pt_new->pre = NULL;
pt_new->next = NULL;
return add_name(pt_new);
}
pt_name find_name(char *name)
{
pt_name pt_cur;
if (!g_pt_name_head)
return NULL;
else {
pt_cur = g_pt_name_head;
do {
if (strcmp(pt_cur->name, name) == 0){
return pt_cur;
} else {
pt_cur = pt_cur->next;
}
} while(pt_cur);
}
return NULL;
}
int32_t del_name(pt_name pt_del)
{
pt_name pt_cur;
pt_name pt_pre;
pt_name pt_next;
if (g_pt_name_head == pt_del)
g_pt_name_head = pt_del->next;
/* 释放 */
else {
pt_cur = g_pt_name_head->next;
while (pt_cur){
if (pt_cur == pt_del){
/* 从链表中删除 */
pt_pre = pt_cur->pre;
pt_next = pt_cur->next;
pt_pre->next = pt_next;
if (pt_next){
pt_next->pre = pt_pre;
}
} else {
pt_cur = pt_cur->next;
}
}
}
free(pt_del->name);
free(pt_del);
return 0;
}
int32_t del_one_name(void)
{
pt_name pt_find;
char name[32];
printf("enter the name:");
scanf("%s", name);
pt_find = find_name(name);
if(!pt_find) {
printf("No the name\n\n");
return -1;
}
return del_name(pt_find);
}
int32_t list_all_name(void)
{
pt_name pt_cur;
int i = 0;
pt_cur = g_pt_name_head;
while (pt_cur){
i++;
printf("%02d : %s\r\n", i, pt_cur->name);
pt_cur = pt_cur->next;
}
printf("\n\n");
return 0;
}
int main(int argc, char **argv)
{
char ch = ' ';
while (1) {
printf("<l> List all names\r\n");
printf("<a> add one name\r\n");
printf("<d> del one name\r\n");
printf("<x> exit\r\n");
printf("\r\n");
ch = getchar();
switch (ch){
case 'l':
list_all_name();
break;
case 'a':
add_one_name();
break;
case 'd':
del_one_name();
break;
case 'x':
return 0;
}
}
return 0;
}