![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
C
Hongggggggg
嵌入式ICU
展开
-
宏定义的嵌套
宏定义的嵌套原创 2023-01-12 11:37:46 · 2307 阅读 · 3 评论 -
设计模式之单例模式(C语言)
介绍: 单例模式是一种创建型设计模式,又称为单件模式,是最简单的设计模式之一;作用:保证一个类永远都只有一个实例;如果你已经创建了一个实例, 过一会儿还想再创建一个新的实例, 此时获得到的实例是之前已创建的实例, 而不是一个新的实例;提供一个访问该实例的全局接口;解决问题:控制实例数量;避免全局使用的实例频繁创建与销毁;类比: 地球只有一个,无论在什么场景下,我们口中所说的地球都是同一个地球;代码示例:/*共享资源大小*/#define SHARED_MEM_SI原创 2021-12-02 09:30:00 · 414 阅读 · 0 评论 -
typeof关键字
typeof是C语言中的一个关键字,与sizeof类似,作用是得到参数的具体类型;示例:定义一个与a类型相同的变量b:int a;typeof(a) b;在linux中有个很经典的用法如下:#define __MIN(A,B) ({ typeof(A) __a = (A);\ typeof(B) __b = (B);\ __a < __b ? __a : __b; })使用typeof可以让这个宏具有泛化能力,无论什么传入类型的参数传入,都可以有效的判别大原创 2021-12-30 15:13:19 · 407 阅读 · 0 评论 -
侵入式链表
普通链表:我们经常使用的普通链表是每个节点的next指针指向下一个节点的首地址:具体代码实现如下:struct link{ int data; struct link* next;}普通链表的缺点:一条链表上的所有节点的数据类型需要完全一致对某条链表的操作如插入,删除等只能对这种类型的链表进行操作,如果链表的类型换了,就要重新再封装出一套一样的操作,泛化能力差;侵入式链表:侵入式链表的节点的链接成员指向的是下一个节点的链接成员:节点结构如下:typ原创 2021-12-29 15:24:08 · 1522 阅读 · 0 评论 -
指针数组和数组指针
指针数组:本质是数组,数组里的每个元素是指针类型的示例:int *p[4] = {"abc", "def", "123", "456"};int a[3][4];int *p[3];for(int i = 0; i < 3; i++){ p[i] = a[i];}数组指针:本质是指针,一个指向数组首地址的指针,也称为行指针示例:int a[3][4];int (*p)[4];//定义一个数组指针,指向包含4个元素的一维数组p = a; //将二维数组的首地址赋值给原创 2021-12-08 09:30:00 · 319 阅读 · 0 评论 -
常量指针和指针常量
常量指针:const char *p或char const *pp指向的地址所对应的值为const类型,因此不可修改,但p是可修改的示例:void const_test(const char *p){ p = 1;//正确,p是可修改的 *(p + 1) = 'a';//错误,p指向的内存地址对应的值是不可修改的(使用*p会报错)}指针常量:char* const pconst 修饰的为p,所以p不可修改,但p所指向的内存地址对应的值可以修改示例:void const_tes原创 2021-12-07 09:30:00 · 368 阅读 · 0 评论 -
位运算技巧
判断一个数的二进制表示中有多少个1uint8_t count_bit1(int value){ int cnt = 0; while(value) { value &= (value-1); cnt ++; } return cnt;}判断一个数是否为2的N次方:bool is_2_power(int value){ return !(value & (value - 1));}两数交换:void swap(int* a, int* b){原创 2021-12-06 09:30:00 · 57 阅读 · 0 评论 -
内存分布结构
内存分布结构如下所示:代码区:存放代码的位置,只读;常量区:存放常量(如变量名字,非零的初始化值,字符串,const常量等),只读;静态区、全局区:存放全局变量和静态变量,具体分为两个段,.bss段和.data段;.bss段:存放未初始化的和初始化为0的全局变量或者静态变量;.data段:初始化不为0的全局变量或者静态变量;堆:程序运行期间动态分配malloc所使用的区域;栈:用于存放地址(用于函数的现场恢复)、临时变量(函数内部定义的变量,或是函数定义的参数)等;原创 2021-12-05 14:59:25 · 296 阅读 · 0 评论 -
消息订阅机制(C语言)
为了实现代码的解耦,根据设计模式中的观察者模式设计了一个消息订阅的机制。当某个模块需要得到某些消息的通知时,可以使用topic_subscribe订阅想要的消息,并将回调函数注册进去,当消息使用msg_notify通知时,会触发已经注册了的回调;整体代码如下:.h文件#ifndef __MSG_SUBSCRIBE_H_#define __MSG_SUBSCRIBE_H_/*消息的类型都在这个枚举里*/typedef enum{ ON_OFF_STATE, LIGHTNE原创 2021-12-04 09:30:00 · 1949 阅读 · 0 评论 -
container_of宏
C语言中有这样一个宏container_of,它的作用是通过结构体的成员,结构体成员的地址以及结构体的类型来获取结构体的首地址,原型如下:#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})参数说明:原创 2021-12-01 09:30:00 · 292 阅读 · 0 评论 -
C 库宏 - offsetof()
C语言中有这样一个宏offsetof,它的作用是计算结构体成员相对于结构体的偏移,原型如下:#define offsetof(type, member) (size_t) &((type*)0)->member参数说明:type:结构体类型member:结构体成员原理分析:偏移 = 成员地址 - 结构体地址,若结构体地址为0,则偏移 = 成员地址;示例:#include <stdio.h>#define offsetof(type, mem原创 2021-11-26 16:42:55 · 632 阅读 · 0 评论 -
C语言判断一个值是否在枚举里
假设我们定义这样一个枚举,枚举里的内容并非是连续的顺序:typedef enum{ SCAN = 1, READY = 5, ADV = 7, CONN = 18, INIT = 20,}State_e;此时如果有一个值state,如何判断state是否属于枚举中的内容呢?通常我们会用switch-case来判断state是否属于枚举中的内容,代码如下:switch(state){ case SCAN: case READY:原创 2021-11-29 09:30:00 · 5192 阅读 · 0 评论 -
C语言中的X-MACRO技巧
X-Macro只是一种宏的使用技巧,并不是什么特殊的语法,但却在实际应用中十分高效简洁,且拓展性非常强;首先我们介绍一下#define与#undef的用法:#define X_MACRO(a, b) a#undef X_MACRO#define X_MACRO(a, b) b#undef X_MACRO示例:#define X_MACRO(a, b) aint x = X_MACRO(10, 100)#undef X_MACRO #define X_MACRO(a, b) b原创 2021-11-28 09:30:00 · 1969 阅读 · 0 评论 -
C语言常用预定义宏
预定义宏是C标准提供的一组宏,可以让我们很方便处理一些特定信息。常用的预定义宏如下:宏描 述类型__DATE__当前源文件的编泽日期字符串__FILE__当前源文件的名称字符串__LINE__当前源义件中的行号整形__TIME__当前源文件的最新编译吋间字符串示例:#include <stdio.h>void main(void){ printf("File: %s \r\n \原创 2021-11-26 09:30:00 · 951 阅读 · 0 评论 -
C语言定义带默认参数的函数
我们之前介绍过可变参数宏与逗号运算符,将两者相结合的话可以定义出以下形式的宏:#define func(...) __func((default, ##__VA_ARGS__))当在func()里不填写任何内容的时候,正常情况下宏展开后会是func((default,)),但由于##__VA_ARGS__会将前面多余的逗号忽略,所以宏展开后就相当于__func((default));当在func()括号里填写有效值的时候,根据逗号运算符的值等于最后一个表达式的值的性质,宏会被展开为__func((#原创 2021-11-21 23:58:38 · 2182 阅读 · 0 评论 -
C语言数组初始化技巧
C99支持这样一种数组初始化方式,可以很方便的对数组进行初始化:int arr[10] = {100, [1 ... 7] = 99, 98, 97};省略号的两边的数字代表元素的下标,实际意义是将第一个元素至第7个元素均赋值为99,注意,省略号两边均有一个空格示例:#include <stdio.h>void main(void){ int arr[5] = {100, [1 ... 3] = 50, 10}; for (int i = 0; i <原创 2021-11-22 09:30:00 · 387 阅读 · 2 评论 -
C语言运算符优先级
优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右 () 圆括号 (表达式)/函数名(形参表) . 成...原创 2021-11-20 09:30:00 · 220 阅读 · 0 评论 -
逗号运算符
概述: 逗号运算符是C语言中提供的一种特殊的运算符,它的优先级最低,具体作用是将多个表达式连接起来,组成一个更大的表达式,也称之为逗号表达式。一般形式如下:(表达式1,表达式2,表达式3,...,表达式n)性质:逗号表达式的优先级是最低的 求解过程是从左至右,既先算表达式1,然后是表达式2,最后是表达式n 逗号表达式的结果为最后一个表达式的结果,既表达式n的结果示例:#include <stdio.h&...原创 2021-11-19 14:39:43 · 7951 阅读 · 1 评论 -
C语言中不同类型之间的混合运算
规则:char和short类型参与运算的时候都会先转为int类型再运算char + short => int + int所有浮点类型的运算都会转为double类型进行运算float + float => double + double两种数据类型相同但一个是有符号,一个是无符号,则转为无符号类型int + unsigned int => unsigned int + unsigned int低类型会转为高类型int + long => long + l原创 2021-11-18 10:37:16 · 3679 阅读 · 0 评论 -
C语言可变参数宏__VA_ARGS__
介绍:可变参数宏__VA_ARGS__是C99中引入的一个宏,表示一个或多个参数,类似函数的可变参数中的省略号;使用方法:#define debug(format, ...) printf(format, ##__VA_ARGS__)void main(void){ debug("%s: %d\r\n", "debug", 100);}输出 >>> debug: 100##的作用:如果不带##,__V...原创 2021-11-16 15:52:32 · 11196 阅读 · 0 评论 -
C语言中可变参数的实现
原理函数参数是从右向左线性连续依次入栈,如果我们可以知道可变参数列表的前一个参数的地址和类型,就可以得知可变参数列表的首地址,进而根据每个参数的类型取出相应的数据。简单来说就是将栈里面的数据,按照指定类型的大小,依次取出。具体实现:代码如下(示例):#include <stdarg.h>/*最后一个参数必须是省略号既...*/int Sum(int n, ...){ int sum = 0; va_list ap; //用于指向可变参数的...原创 2021-11-12 17:26:45 · 1122 阅读 · 0 评论