编译连接过程


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_addlist_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-1if(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!=NULLwhile(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;}
结构体初始化
指针

浮点数比较




C-串复制

斐波那契数列


