之前看见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 ;        
  • }
  • 复制代码
    运行结果:


    来源:https://blog.csdn.net/morixinguan/article/details/100188149