├── res ├── list.c ├── sort.c ├── main.c ├── tree.c └── stack.c ├── Image ├── mergesort.gif ├── quicksort.gif ├── shellsort.gif ├── bubblesort.gif ├── insertsort.gif ├── selectsort.gif └── sortcompare.png ├── .gitignore ├── README.md └── md ├── 数据结构与简单算法.md ├── 经典排序算法.md └── Base_C.md /res/list.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/res/list.c -------------------------------------------------------------------------------- /res/sort.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/res/sort.c -------------------------------------------------------------------------------- /Image/mergesort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/Image/mergesort.gif -------------------------------------------------------------------------------- /Image/quicksort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/Image/quicksort.gif -------------------------------------------------------------------------------- /Image/shellsort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/Image/shellsort.gif -------------------------------------------------------------------------------- /Image/bubblesort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/Image/bubblesort.gif -------------------------------------------------------------------------------- /Image/insertsort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/Image/insertsort.gif -------------------------------------------------------------------------------- /Image/selectsort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/Image/selectsort.gif -------------------------------------------------------------------------------- /Image/sortcompare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alzhst/Firmware-Engineer-Knowledge/HEAD/Image/sortcompare.png -------------------------------------------------------------------------------- /res/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void myswap(int* x, int* y); 4 | 5 | int main() 6 | { 7 | int array[] = {5,4,2,1,8,10,23,6}; 8 | int i = 0; 9 | int j = 0; 10 | for(i=0;i<7;i++) 11 | { 12 | for(j=0;j<7-i;j++) 13 | { 14 | if(array[j] > array[j+1]) 15 | myswap(array+j,array+j+1); 16 | } 17 | } 18 | for(i = 0; i<8;i++) 19 | { 20 | printf("%d\n",array[i]); 21 | } 22 | return 0; 23 | } 24 | 25 | void myswap(int* x, int* y) 26 | { 27 | int temp = *x; 28 | *x = *y; 29 | *y = temp; 30 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /res/tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct node 5 | { 6 | char ch; 7 | struct node* left; 8 | struct node* right; 9 | }TreeNode; 10 | 11 | typedef TreeNode* PtrTreeNode; 12 | typedef PtrTreeNode Tree; 13 | 14 | 15 | 16 | //创建二叉树 17 | void CreateTree(Tree *T) 18 | { 19 | char ch; 20 | scanf("%c",&ch); 21 | 22 | if(ch == '*') 23 | { 24 | *T = NULL; 25 | } 26 | else 27 | { 28 | *T = (Tree)malloc(sizeof(TreeNode)); 29 | (*T)->ch = ch; 30 | CreateTree(&(*T)->left); 31 | CreateTree(&(*T)->right); 32 | } 33 | } 34 | 35 | //前序遍历 36 | void PreShow(Tree T) 37 | { 38 | if(T == NULL) 39 | return; 40 | printf("%c ",T->ch); 41 | PreShow(T->left); 42 | PreShow(T->right); 43 | } 44 | 45 | //中序遍历 46 | void MidShow(Tree T) 47 | { 48 | if(T == NULL) 49 | return; 50 | MidShow(T->left); 51 | printf("%c ",T->ch); 52 | MidShow(T->right); 53 | } 54 | 55 | //后序遍历 56 | void BackShow(Tree T) 57 | { 58 | if(T == NULL) 59 | return; 60 | BackShow(T->left); 61 | BackShow(T->right); 62 | printf("%c ",T->ch); 63 | } 64 | 65 | 66 | int main() 67 | { 68 | Tree t; 69 | CreateTree(&t); 70 | PreShow(t); 71 | printf("\n"); 72 | MidShow(t); 73 | printf("\n"); 74 | BackShow(t); 75 | printf("\n"); 76 | return 0; 77 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **计划** 2 | =========== 3 | ##**任务选项** 4 | - [] C语言基础 5 | - [] 数据结构 + 简单算法 6 | - [] 硬件基础知识 7 | - [] 单片机基础知识(51+STM32) 8 | - [] μC/OS II(原理+移植) 9 | - [] 协议时序分析(IIC,SPI,UART,232/485) 10 | - [] 网络(TCP/IP,网络基础知识) 11 | - [] FPGA(基础知识+FIFO+RS编解码器) 12 | - [] 杂项(shell,git) 13 | 14 | 15 | #目录 16 | * C语言基础 17 | * 数据类型 18 | * 位运算 19 | * 数组与指针 20 | * 结构 21 | * 预处理器 22 | * static、const、volatile 23 | * 数据结构 + 简单算法 24 | * 链表 25 | * 栈 26 | * 队列 27 | * 二叉树 28 | * 经典排序算法 29 | * 冒泡 30 | * 快排 31 | * 选择 32 | * 插入 33 | * 堆排序 34 | * 希尔排序 35 | * 二分算法 36 | * 动态规划 37 | * 硬件基础知识 38 | * 三极管 39 | * 寄存器 40 | * 数制 41 | * 存储器知识 42 | * 单片机基础知识(51+STM32) 43 | * 时钟电路 44 | * 输入输出 45 | * 中断 46 | * 汇编 47 | * μC/OS II(原理+移植) 48 | * 原理 49 | * 任务 50 | * 时钟与中断 51 | * 任务同步与通信 52 | * 信号量 53 | * 互斥信号量 54 | * 消息邮箱 55 | * 消息队列 56 | * 信号量集 57 | * 内存管理 58 | * 移植 59 | * 51 60 | * STM32 61 | * 协议时序分析(IIC、SDIO、SPI、UART) 62 | * IIC 63 | * SDIO 64 | * SPI 65 | * UART 66 | * 网络(TCP/IP,网络基础知识) 67 | * 网络层次 68 | * OSI七层模型 69 | * TCP/IP 70 | * UDP 71 | * 路由协议 72 | * ARP/PARP 73 | * DNS 74 | * FPGA 75 | * Verilog 语言 76 | * 模块 77 | * 状态机 78 | * 待续 79 | * 杂项 80 | * shell 81 | * git 82 | * 项目 83 | * 蓝牙锁 84 | * RS编解码器 85 | 86 | 87 | -------------------------------------------------------------------------------- /res/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct node 5 | { 6 | struct node* next; 7 | int num; 8 | }Node; 9 | typedef Node* NodePtr; 10 | typedef Node* Stack; 11 | 12 | 13 | //函数声明 14 | Stack StackCreate(void); 15 | int IsStackEmpty(Stack stack); 16 | int StackPush(Stack stack, int x); 17 | int StackPop(Stack stack); 18 | int StackTop(Stack stack); 19 | void StackDestory(Stack stack); 20 | 21 | 22 | 23 | //创建一个栈 24 | Stack StackCreate(void) 25 | { 26 | NodePtr Head = (NodePtr)malloc(sizeof(Node)); 27 | if(Head == NULL) 28 | { 29 | printf("No free space\n"); 30 | return NULL; 31 | } 32 | Head->next = NULL; 33 | return Head; 34 | } 35 | 36 | //判断栈是否为空 37 | int IsStackEmpty(Stack stack) 38 | { 39 | return stack->next == NULL; 40 | } 41 | 42 | //入栈 43 | int StackPush(Stack stack, int x) 44 | { 45 | NodePtr new = (NodePtr)malloc(sizeof(Node)); 46 | if(new == NULL) 47 | { 48 | printf("No free space\n"); 49 | return -1; 50 | } 51 | new->num = x; 52 | new->next = stack->next; 53 | stack->next = new; 54 | return 0; 55 | } 56 | 57 | //出栈 58 | int StackPop(Stack stack) 59 | { 60 | if(!IsStackEmpty(stack)) 61 | { 62 | NodePtr Temp = stack->next; 63 | stack->next = Temp->next; 64 | free(Temp); 65 | return 0; 66 | } 67 | printf("Empty Stack\n"); 68 | return -1; 69 | } 70 | 71 | //获取栈顶信息 72 | int StackTop(Stack stack) 73 | { 74 | if(IsStackEmpty(stack)) 75 | { 76 | printf("Empty Stack\n"); 77 | return 0; 78 | } 79 | return stack->next->num; 80 | } 81 | 82 | //销毁栈 83 | void StackDestory(Stack stack) 84 | { 85 | NodePtr p = stack->next; 86 | while(p != NULL) 87 | { 88 | NodePtr Temp = p->next; 89 | free(p); 90 | p = Temp; 91 | } 92 | } 93 | 94 | 95 | int main(void) 96 | { 97 | Stack s = StackCreate(); 98 | for(int i = 1; i <= 5;i++) 99 | StackPush(s,i); 100 | for(int i = 1; i <= 3;i++) 101 | StackPop(s); 102 | for(int i = 1; i <= 3;i++) 103 | StackPush(s,i*10); 104 | for(int i = 0; i < 5; i++) 105 | { 106 | printf("%d ",StackTop(s)); 107 | StackPop(s); 108 | } 109 | printf("\n"); 110 | StackDestory(s); 111 | printf("%d ",StackTop(s)); 112 | return 0; 113 | } -------------------------------------------------------------------------------- /md/数据结构与简单算法.md: -------------------------------------------------------------------------------- 1 | 数据结构与简单算法 2 | ======================= 3 | 4 | ## **链表** 5 | * 定义 :为了避免删除与插入时的线性开销,可以允许表不是连续存储的。链表的每一个结构均包含表元素和指向包含该元素后继元的结构的指针,最后一个元素的Next指针指向NULL。 6 | * 节点定义 7 | ```C 8 | typedef struct node 9 | { 10 | struct node *next; 11 | int num; 12 | } 13 | Node; 14 | typedef struct node* NodePtr; 15 | ``` 16 | * 创建链表(带表头) 17 | ```C 18 | NodePtr ListCreate(void) 19 | { 20 | NodePtr Head = (NodePtr)malloc(sizeof(Node)); 21 | if(NULL == Head) 22 | { 23 | printf("out of sapce"); 24 | return NULL; 25 | } 26 | Head->num = 0; 27 | Head->next = NULL; 28 | return Head; 29 | } 30 | ``` 31 | * 判断链表为空 32 | ```C 33 | int IsListEmpty(NodePtr L) 34 | { 35 | return L->next == NULL; 36 | } 37 | ``` 38 | * 插入一个节点 39 | ``` 40 | int ListInsertNode(NodePtr L,int x , NodePtr p) 41 | { 42 | NodePtr new = (NodePtr)malloc(Node); 43 | if(new == NULL) 44 | { 45 | printf("out of sapce"); 46 | return -1; 47 | } 48 | new->num = x; 49 | new->next = p->next; 50 | p->next = new; 51 | return 0; 52 | } 53 | ``` 54 | * 删除一个节点 55 | ```C 56 | int ListDeleteNode(NodePtr L,int x) 57 | { 58 | NodePtr p = L; 59 | while(p->next != NULL && p-next->num != x) 60 | { 61 | p = p->next; 62 | return -1; 63 | } 64 | if(p->next != NULL) 65 | { 66 | NodePtr Temp = p->next; 67 | p->next = Temp->next; 68 | free(Temp); 69 | return 0; 70 | } 71 | return -2; 72 | } 73 | ``` 74 | * 删除链表 75 | ```C 76 | void ListDelete(NodePtr L) 77 | { 78 | NodePtr p = L->next; 79 | while(p != NULL) 80 | { 81 | NodePtr temp = p->next; 82 | free(p); 83 | p = temp; 84 | } 85 | } 86 | ``` 87 | 88 | ## **栈** 89 | * 定义:栈是一种先入后出的结构,程序的运行就是放在栈空间进行的。 90 | * 创建栈 91 | ```C 92 | Stack StackCreate(void) 93 | { 94 | NodePtr Head = (NodePtr)malloc(sizeof(Node)); 95 | if(Head == NULL) 96 | { 97 | printf("No free space\n"); 98 | return NULL; 99 | } 100 | Head->next = NULL; 101 | return Head; 102 | } 103 | ``` 104 | * 入栈 105 | ```C 106 | int StackPush(Stack stack, int x) 107 | { 108 | NodePtr new = (NodePtr)malloc(sizeof(Node)); 109 | if(new == NULL) 110 | { 111 | printf("No free space\n"); 112 | return -1; 113 | } 114 | new->num = x; 115 | new->next = stack->next; 116 | stack->next = new; 117 | return 0; 118 | } 119 | ``` 120 | * 出栈 121 | ```C 122 | int StackPop(Stack stack) 123 | { 124 | if(!IsStackEmpty(stack)) 125 | { 126 | NodePtr Temp = stack->next; 127 | stack->next = Temp->next; 128 | free(Temp); 129 | return 0; 130 | } 131 | printf("Empty Stack\n"); 132 | return -1; 133 | } 134 | ``` 135 | * 获取栈顶数据 136 | ```C 137 | int StackTop(Stack stack) 138 | { 139 | if(IsStackEmpty(stack)) 140 | { 141 | printf("Empty Stack\n"); 142 | return 0; 143 | } 144 | return stack->next->num; 145 | } 146 | ``` 147 | * 销毁栈 148 | ```C 149 | void StackDestory(Stack stack) 150 | { 151 | NodePtr p = stack->next; 152 | while(p != NULL) 153 | { 154 | NodePtr Temp = p->next; 155 | free(p); 156 | p = Temp; 157 | } 158 | } 159 | ``` 160 | 161 | ## **树** 162 | * 基础知识 163 | * 一颗树是由N个节点与N-1条边组成的 164 | * 没有儿子的节点叫叶子节点,没有父节点的叫根节点。 165 | * 路径是N1到N(i+1)的序列,这个序列中,每一个节点是下一个节点的父亲,路径的长就是该路径上边的数目。每一个节点到其自身都有一个长为0路径。 166 | * 任意节点的深度是从根节点到该节点的唯一路径的长,根节点的深度为0. 167 | * 任意节点的高是从该节点到一片树叶的最长路径的长,所有树叶的高都为0. 168 | * 树的深度等于它的最深的树叶的深度,树的高等于根节点的高,树的高与深度相等 169 | 170 | 171 | -------------------------------------------------------------------------------- /md/经典排序算法.md: -------------------------------------------------------------------------------- 1 | [经典排序算法](https://www.cnblogs.com/onepixel/articles/7674659.html "十大经典排序") 2 | ======================= 3 | 4 | * 冒泡排序 5 | * 选择排序 6 | * 插入排序 7 | * 快速排序 8 | * 归并排序 9 | * 希尔排序 10 | * 堆排序 11 | * 桶排序 12 | 13 | * 各排序算法比较 14 | ![排序算法比较](https://github.com/alzhst/Firmware-Engineer-Knowledge/raw/master/Image/sortcompare.png) 15 | 16 | #### **冒泡排序** 17 | * 算法概述:比较相邻的两个元素,如果顺序异常,就进行交换,每轮遍历后,最末尾的值就是元素中的极值。 18 | * 动画演示 19 | ![冒泡排序](https://github.com/alzhst/Firmware-Engineer-Knowledge/raw/master/Image/bubblesort.gif) 20 | * 示例代码 21 | 22 | ```C 23 | //加入flag标准位进行简单优化 24 | int bubblesort(int* array , int len) 25 | { 26 | int i = 0; 27 | int j = 0; 28 | int flag = TRUE; 29 | if(array == NULL) 30 | { 31 | return -1; 32 | } 33 | for(i = 0;i < len -1 && flag; i++) 34 | { 35 | flag = FALSE; 36 | for(j = 0; j array[j+1]) 39 | { 40 | flag = TRUE; 41 | swap(array+j,array+j+1); 42 | } 43 | } 44 | } 45 | return 0; 46 | } 47 | ``` 48 | #### **选择排序** 49 | * 算法概述:首先在序列中找到极值,放于起始位,然后在剩下的序列中找到极值,放在已排序序列之后,直到所有序列排列完毕。 50 | * 动画演示 51 | ![选择排序](https://github.com/alzhst/Firmware-Engineer-Knowledge/raw/master/Image/selectsort.gif) 52 | * 示例代码 53 | ```C 54 | int selectsort(int* array , int len) 55 | { 56 | int i = 0; 57 | int j = 0; 58 | if(array == NULL) 59 | { 60 | return -1; 61 | } 62 | for(i = 0;i < len -1; i++) 63 | { 64 | int min = i; 65 | for(j = i+1; j < len; j++) 66 | { 67 | if(array[j] < array[min]) 68 | { 69 | min = j; 70 | } 71 | } 72 | swap(array+i,array+min); 73 | } 74 | return 0; 75 | } 76 | ``` 77 | #### **插入排序** 78 | * 算法概述:插入排序先构建有序序列,遍历未排序序列,逐个按照顺序插入有序序列中。 79 | * 动画演示 80 | ![插入排序](https://github.com/alzhst/Firmware-Engineer-Knowledge/raw/master/Image/insertsort.gif) 81 | * 示例代码 82 | ```C 83 | int insertsort(int* array,int len) 84 | { 85 | int i = 0; 86 | int j = 0; 87 | if(array == NULL) 88 | { 89 | return -1; 90 | } 91 | for(i = 0; i < len; i++) 92 | { 93 | int pre = i - 1; 94 | int current = array[i]; 95 | while(pre >= 0 && current < array[pre]) 96 | { 97 | array[pre+1]=array[pre]; 98 | pre--; 99 | } 100 | array[pre+1] = current; 101 | } 102 | 103 | } 104 | ``` 105 | ### 希尔排序 106 | * 算法描述: 希尔排序是一种缩小增量的插入排序。对于序列,先间隔排序,然后不断缩小间隔,直到为1. 107 | * 动画演示: 108 | ![希尔排序](https://github.com/alzhst/Firmware-Engineer-Knowledge/raw/master/Image/shellsort.gif) 109 | * 示例代码 110 | ``` 111 | int shellsort(int *array,int len) 112 | { 113 | int gap = 0; 114 | int i = 0; 115 | int j = 0; 116 | for(gap = len / 2;gap > 0;gap /= 2) 117 | { 118 | for(i = 0; i < gap; i++) 119 | { 120 | for(j = gap + i; j < len; j += gap) 121 | { 122 | int current = array[j]; 123 | k = j - gap; 124 | while(k >= 0 && current < array[k]) 125 | { 126 | array[k+gap] = array[k]; 127 | k -= gap; 128 | } 129 | array[k+gap] = current; 130 | } 131 | } 132 | ] 133 | return 0; 134 | } 135 | ``` 136 | ### 归并排序 137 | * 算法描述: 归并排序将序列不断划分为子序列,然后使子序列有序,最后合并各个有序的子序列为一个完整的序列 138 | * 动画演示 139 | ![归并排序](https://github.com/alzhst/Firmware-Engineer-Knowledge/raw/master/Image/mergesort.gif) 140 | * 示例代码 141 | ```C 142 | //将两个有序序列合并 143 | void mergearray(int* a,int first,int mid,int last,int *temp) 144 | { 145 | int k = 0; 146 | int i = first; 147 | int j = mid+1; 148 | while(i <= mid && j<=last) 149 | { 150 | if(a[i] < a[j]) 151 | temp[k++] = a[i++]; 152 | else 153 | temp[k++] = a[j++]; 154 | } 155 | while(i <= mid) 156 | temp[k++] = a[i++]; 157 | while(j <= last) 158 | temp[k++] = a[j++]; 159 | for(i = 0 ;i < k;i++) 160 | a[first+i] = temp[i]; 161 | } 162 | 163 | int sort(int *a,int first,int last,int *temp) 164 | { 165 | if(first < last) 166 | { 167 | int mid = (last+first)/2; 168 | sort(a,first,mid,temp); 169 | sort(a,mid+1,last,temp); 170 | mergearray(a,first,mid,last,temp); 171 | } 172 | } 173 | 174 | //归并排序 175 | int mergesort(int *array,int len) 176 | { 177 | int temp[len]; 178 | sort(array,0,len,temp); 179 | } 180 | ``` 181 | 182 | ### 快速排序 183 | * 算法描述:快速排序 184 | 快速排序采用一种分治法,取一个基准数,让其左边都是比它小,右边都比它大,递归方法重复,完成排序 185 | * 动画演示 186 | ![快速排序](https://github.com/alzhst/Firmware-Engineer-Knowledge/raw/master/Image/quicksort.gif) 187 | * 示例代码 188 | ```C 189 | void qsort(int* array,int first,int last) 190 | { 191 | if(first < last) 192 | { 193 | int i = first; 194 | int j = last; 195 | int temp = array[first]; 196 | while(i temp) 199 | j--; 200 | if(i> |右移| 93 | | ~ |按位取反| 94 | 95 | * 常用技巧 96 | 1. 取一个数的指定位 97 | ```C 98 | unsigned char a = 0xF3; 99 | a &= 0x0F;//取低4位 100 | ``` 101 | 2.对数据某位置1 102 | ```C 103 | unsigned char a = 0xF3; 104 | a |= 0x08;//第4位置1 105 | ``` 106 | 3.对数据某位置0 107 | ```C 108 | unsigned char a = 0xF3; 109 | a &= ~0x08;//第4位置0 110 | ``` 111 | 4.某1位置0或1 112 | ``` 113 | #define setbit(X,Y) X |= (1<` 278 | 279 | ### 宏替换 280 | `#define 名字 替换文本` 281 | * 标识符别名 282 | ```C 283 | #define BUFFER_SIZE 1024 284 | //宏体换行需要在行末加反斜杠\ 285 | #define NUMBERS 1,\ 286 | 2,\ 287 | 3 288 | ``` 289 | ### 宏函数 290 | `宏名之后带括号的宏被认为是宏函数,在预处理阶段,宏函数会被展开。相较于普通函数,执行效率会提高,但代码体积大,没有语法检查,更危险` 291 | 292 | * 注意问题:完全替换,不做语法检查,需注意以下情况 293 | 1.运算符优先级,完全替换,最好加上小括号如`#define ADD(x,y) ((x)+(y))` 294 | 2.分号吞噬:宏函数使用循环时,建议使用do while,不使用for,while; 295 | 3.宏参数重复调用,若宏函数如`#define min(X,Y) ((X) < (Y) ? (X) : (Y))`,则调用`min(x+y,foo(z))`时,会展开成`((x+y) < (foo(z)) ? (x+y) : (foo(z))),foo函数被执行两次, 296 | 4.对自身的递归调用,宏只会展开一次。若`#define foo(4+foo)`,`foo`展开后为`4+foo`,foo不会被识别。 297 | 298 | ### 条件包含 299 | * 避免头文件重复包含 300 | `#ifndef XXX_H` 301 | `#define XXX_H` 302 | * 条件编译,可利用宏适应多环境,可以配置DEBUG 303 | ```C 304 | //条件编译 305 | #define CPU_A 306 | //#define CPU_B 307 | #if define CPU_A 308 | CPU_A(XXXXX); 309 | #elif define CPU_B 310 | CPU_B(XXXXX); 311 | #else 312 | CPU_O(XXXXX); 313 | #endif 314 | //DEBUG 315 | #define DEBUG 316 | #if define DEBUG 317 | DEBUG(XXXXX); 318 | #endif 319 | ``` 320 | 321 | ## **变量修饰符** 322 | ### const 323 | * 定义:关键字const是用来定义常量的,如果一个变量被const修饰,那么他的值就不能被修改。 324 | * 优点 325 | * 可以保护被修饰的变量,防止被意外修改,增加程序健壮性。 326 | * 编译器优化(保存在符号表中),提高效率 327 | * 典型用法 328 | * 修饰局部变量,n的值不可改变。 329 | `const int n = 5;` 330 | `int const n = 5;` 331 | * 修饰常量字符串,确保在s[1]赋值时,编译报错。 332 | `const char* s = "abcdefg;"` 333 | * 常量指针:指针指向的内容是常量 334 | `const int * p;` 335 | `int const * p;` 336 | * 常量指针不能通过该指针改变变量的值,但是可以通过其他方式改变变量的值 337 | * 常量指针指向的内容不能改变,但可以改变指针本身的值。 338 | 339 | ```C 340 | int a = 1; 341 | int b = 2 342 | const int *p = &a; 343 | a = 3; 344 | p = &b; 345 | ``` 346 | * 指针常量: 指针本身为常量,不能指向其他地址。 347 | `int *const p;` 348 | * 指针常量本身指向的地址不能变,但是该地址中的值是可以改变的 349 | 350 | ```C 351 | int a = 0; 352 | int *const p = &a; 353 | *p = 5; 354 | ``` 355 | * 指向常量的常指针:指针本身不可以修改,指向的值也不可以修改,但是可以通过其他指针改变变量的值 356 | `const int *const p` 357 | 358 | * 修饰参数 359 | * 防止指针指向的内容被修改 360 | `void cmp(const char *s1,const char *s2)` 361 | * 防止修改指针指向的地址 362 | `void swap(int *const p1,int *const p2)` 363 | * 修饰返回值:如果返回值为常量指针,则只能赋值给相同类型的常量指针。 364 | `const char * GetString(void);` 365 | * 修饰全部变量:防止全局变量被修改。 366 | 367 | 368 | ### static 369 | * 修饰局部变量 370 | * 被static修饰的局部变量不放在栈内存中,放在静态存储区。所以不会随着函数调用结束被释放。 371 | * static 局部变量只会在第一次时被初始化,且只能初始化1次,未初始化则默认为0; 372 | * 修饰全局变量与函数 373 | * 被static 修饰的全局变量及函数只能在当前的源文件中访问,可以隐藏数据,降低系统耦合。 374 | 375 | ### volatile 376 | * volatile修饰的变量代表其会直接从内存中重新装载数据,而不是从寄存器中拷贝内容。 377 | * 在部分情况下,变量的值可能会被意想不到的改变,例如中断中的变量或硬件寄存器的值,但是由于编译器优化,程序可能仍然读取寄存器中的拷贝,为了确保每次读写都从源地址读取,需要采用volatile修饰。 378 | ### register 379 | * 数据直接存贮在寄存器中,需要访问时,不需要在RAM中寻址,直接寄存器寻址,速度快,可以提高运行效率。 380 | * 数据放在寄存器中,不能对register变量进行取地址(&)操作。 381 | 382 | 383 | 384 | 385 | 386 | 387 | --------------------------------------------------------------------------------