C语言#和##连接符在项目中的应用(漂亮)

简介: C语言#和##连接符在项目中的应用(漂亮)

之前看见ST官方一个老外的风格,看完之后大赞。看看他是怎么写的:

#ifndef RINGBUFF_HDR_H
#define RINGBUFF_HDR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <stdint.h>
/**
 * \defgroup        RINGBUFF Ring buffer
 * \brief           Generic ring buffer manager
 * \{
 */
/* --- Buffer unique part starts --- */
/**
 * \brief           Buffer function/typedef prefix string
 *
 * It is used to change function names in zero time to easily re-use same library between applications.
 * Use `#define BUF_PREF(x)    my_prefix_ ## x` to change all function names to (for example) `my_prefix_buff_init`
 *
 * \note            Modification of this macro must be done in header and source file aswell
 */
#define BUF_PREF(x)                     ring ## x
/* --- Buffer unique part ends --- */
/**
 * \brief           Buffer structure
 */
typedef struct {
    uint8_t* buff;                              /*!< Pointer to buffer data.
                                                    Buffer is considered initialized when `buff != NULL` and `size` */
    size_t size;                                /*!< Size of buffer data. Size of actual buffer is `1` byte less than value holds */
    size_t r;                                   /*!< Next read pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */
    size_t w;                                   /*!< Next write pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */
} BUF_PREF(buff_t);
uint8_t     BUF_PREF(buff_init)(BUF_PREF(buff_t)* buff, void* buffdata, size_t size);
void        BUF_PREF(buff_free)(BUF_PREF(buff_t)* buff);
void        BUF_PREF(buff_reset)(BUF_PREF(buff_t)* buff);
/* Read/Write functions */
size_t      BUF_PREF(buff_write)(BUF_PREF(buff_t)* buff, const void* data, size_t btw);
size_t      BUF_PREF(buff_read)(BUF_PREF(buff_t)* buff, void* data, size_t btr);
size_t      BUF_PREF(buff_peek)(BUF_PREF(buff_t)* buff, size_t skip_count, void* data, size_t btp);
/* Buffer size information */
size_t      BUF_PREF(buff_get_free)(BUF_PREF(buff_t)* buff);
size_t      BUF_PREF(buff_get_full)(BUF_PREF(buff_t)* buff);
/* Read data block management */
void *      BUF_PREF(buff_get_linear_block_read_address)(BUF_PREF(buff_t)* buff);
size_t      BUF_PREF(buff_get_linear_block_read_length)(BUF_PREF(buff_t)* buff);
size_t      BUF_PREF(buff_skip)(BUF_PREF(buff_t)* buff, size_t len);
/* Write data block management */
void *      BUF_PREF(buff_get_linear_block_write_address)(BUF_PREF(buff_t)* buff);
size_t      BUF_PREF(buff_get_linear_block_write_length)(BUF_PREF(buff_t)* buff);
size_t      BUF_PREF(buff_advance)(BUF_PREF(buff_t)* buff, size_t len);
#undef BUF_PREF         /* Prefix not needed anymore */
/**
 * \}
 */
#ifdef __cplusplus
}
#endif
#endif /* RINGBUFF_HDR_H */

这个老外实现的是一个环形缓冲,然而他巧妙的将ring这个字串去掉,最后阅读代码看到的是非常整齐的:

BUF_PREF(buffer_init)
BUF_PREF(buff_free)
BUF_PREF(buff_write)
BUF_PREF(buff_read)
等等。。。

接下来看看到底是怎么用的:

#define BUF_PREF(x) ring ## x

"##" 表示将左边的字符串和右边的字符串连接起来,但是只能黏贴C语言除了关键字以外的合法标识符 于是上面展开的效果如下:

ring_buffer_init
ring_buffer_free
ring_buffer_write
ring_buffer_read
等等。。。

既然知道了原理,那我在项目上可以这么来用。


之前,你写个LED驱动或者别的可能是这样的,定义了这么多个函数

void led_device_open(void);
void led_device_close(void);
uint8_t led_device_read(void);
uint8_t led_device_write(uint8_t status);
。。。

看起来很统一,我一眼看出这是一个LED的操作方法,但操作一个LED不就是open,close,read,write方法吗?


我们可以让它看起来更优雅:

#define  LED_CLASS(x) led_device_ ## x
void     LED_CLASS(open)(void);
void     LED_CLASS(close)(void);
uint8_t  LED_CLASS(read)(void);
uint8_t  LED_CLASS(write)(uint8_t status);

如果我写另外一个驱动,也是一样有open,close,read,write接口,假设是个FLASH设备。那还是一样的:

#define  FLASH_CLASS(x) flash_device_ ## x
void     FLASH_CLASS(open)(void);
void     FLASH_CLASS(close)(void);
uint8_t  FLASH_CLASS(read)(void);
uint8_t  FLASH_CLASS(write)(uint8_t status);

看起来舒服多了!Good!


那么##和#又有什么区别呢?


##刚刚已经说了,是黏贴字符串


而#表示的是将参数转换为字符串


下面写一个跟#相关的例子:

#include <stdio.h>
#define Print(x) printf("%s %d\n",#x,x);
int main(void)
{
  Print(100);
  return 0 ;  
}

运行结果:

640.png

往期精彩

C语言字符串的另类用法


别瞎找了,你要的C语言经典示例都在这~


C语言表驱动法编程实践(精华帖,建议收藏并实践)


嵌入式C语言代码优化方案(深度好文,建议花时间研读并收藏)

目录
相关文章
|
8月前
|
C语言
C语言中条件操作符的应用
最后,条件操作符是个超级英雄,但不是每个代码问题都需要一个超级英雄来解决。一定要在适当的时候适度的使用它,那么它将成为你的编程工具箱中的一件强力工具。
407 75
|
存储 算法 C语言
通义灵码在考研C语言和数据结构中的应用实践 1-5
通义灵码在考研C语言和数据结构中的应用实践,体验通义灵码的强大思路。《趣学C语言和数据结构100例》精选了五个经典问题及其解决方案,包括求最大公约数和最小公倍数、统计字符类型、求特殊数列和、计算阶乘和双阶乘、以及求斐波那契数列的前20项和。通过这些实例,帮助读者掌握C语言的基本语法和常用算法,提升编程能力。
320 4
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
359 5
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
338 2
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
341 1
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
431 1
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
131 1