一口Linux

文章数:1382 被阅读:1966155

账号入驻

分享几个嵌入式 C 中的实用技巧

最新更新时间:2022-04-21
    阅读数:

大家好,我是 杂烩君 。本次给大家分享几个嵌入式C中的实用技巧。

1、动态绑定、回调函数

回调函数可以达到动态绑定的作用,在一定程度上可以降低层与层之间的耦合。关于回调函数,之前已经有写过一篇: C语言、嵌入式重点知识:回调函数 。可能很多初学的小伙伴可能还不理解回调函数,可以借助下图来理解:

一般函数调用的顺序都是上层函数(调用者)调用下层函数(被调用者)。而通过上图我们可以看到下层模块的函数2调用了上层模块的函数3,这个调用过程与一般的调用过程相反,这个过程叫做回调,这里上层模块的函数3就是回调函数。回调函数的表现形式是函数指针。

C库stdlib.h中带有一个排序函数:qsort函数。这个排序函数的原型为:

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));

参数:

  • base -- 指向要排序的数组的第一个元素的指针。
  • nitems -- 由 base 指向的数组中元素的个数。
  • size -- 数组中每个元素的大小,以字节为单位。
  • compar -- 用来比较两个元素的函数,即函数指针(回调函数)。
int compar(const void *p1, const void *p2);

如果compar返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的左面;

如果compar返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定;

如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的右面。

例子:

#include 
#include 

int compar_int(const void *p1, const void *p2)
{
 return (*((int*)p1) - *((int*)p2));
}

void test_qsort(void)
{
 int arr[5] = {85101100};
 
 printf("排序前:");
 for (int i = 0; i < 5; i++)
 {
  printf("%d ", arr[i]);
 }
 
 qsort((int*)arr, 54, compar_int);
 
 printf("\n排序后:");
 for (int i = 0; i < 5; i++)
 {
  printf("%d ", arr[i]);
 }
}

int main(void)
{
 test_qsort();
 return 0;
}

编译、运行结果:

以上就是本次的分享,如有错误,欢迎指出,谢谢。这是第一弹,后续还会继续分享更多实际开发中实用的编程小技巧及编程经验。欢迎持续关注。本文只是盘点了一些实用小技巧,并不是说无论什么场景下都要这么用,还需具体问题具体分析。

2、使用宏给结构体初始化

如果频繁使用一个结构体的话,使用使用宏来给结构体进行赋值是很方便的一种做法。

例子:

#include 

#define  NEW_RECT(length, width)  {(length), (width)}

typedef struct _Rect
{

 int length;
 int width;
}Rect;

int main(void)
{
 Rect rect = NEW_RECT(105);
 printf("rect length = %d, width = %d\n", rect.length, rect.width);
 return 0;
}

编译、运行结果:

这种方法在RT-Thread的底层gpio驱动中也有见到:

3、结构体内置函数指针

我们常常构造一些结构体来存储数据,然后在一些函数中使用这些结构体。下次不妨把数据与操作数据的函数绑在一起,更清晰明了。

相关文章: 什么是不完全类型?

例子:

#include 

#define  NEW_RECT(length, width)  {(calc_area), (length), (width)}

typedef struct _Rect
{

 int (*calc_area)(struct _Rect *pThis);
 int length;
 int width;
}Rect;

int calc_area(struct _Rect *pThis)
{
 return (pThis->length * pThis->width);
}

int main(void)
{
 Rect rect = NEW_RECT(105);
 printf("rect length = %d, width = %d\n", rect.length, rect.width);
 printf("rect area = %d\n", rect.calc_area(&rect));
 return 0;
}

编译、运行结果:

4、使用do{}while(0)封装宏

#define DBG_PRINTF(fmt, args...)  \
do\
{\
    printf("<> ", __FILE__, __LINE__, __FUNCTION__);\
    printf(fmt, ##args);\
}while(0)

具体说明可查阅往期文章:

C语言、嵌入式中几个非常实用的宏技巧

5、void*

之前在 C语言对象编程第一弹:封装与抽象 中有介绍过 void* void* 其实我们平时都有接触过,比如:

void *malloc(size_t size) ;
void *memcpy(void *destin, void *source, unsigned n);
......

void * 常常用于函数地封装比较多,当然也有用在其它地方,比如在结构体内定义 void* 类型的私有指针方便扩展结构体。我们平时在封装自己的函数时,也可以多考虑看看有没有必要使用 void* 使得函数地通用性更强一些。

end



一口Linux


关注,回复【 1024 】海量Linux资料赠送

精彩文章合集

文章推荐

【专辑】 ARM
【专辑】 粉丝问答
【专辑】 所有原创
专辑 linux 入门
专辑 计算机网络
专辑 Linux驱动


点击“ 阅读原文 ”查看更多分享,欢迎 点分享、收藏、点赞、在看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: TI培训

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved