【宏定义】——编译时检查(二)

文章目录

功能说明

用于在编译时检查一个条件是否为真,如果条件为假则会编译失败,编译器报错

#define TU_STRCAT(a, b) a##b             ///< concat without expand
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat

#define _TU_COUNTER_ __LINE__

#define TU_VERIFY_STATIC(const_expr, _mess) enum                     \
{
      
                                                                          \
    TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1 / (!!(const_expr)) \
}
  • TU_VERIFY_STATIC(1, "static verify successful\r\n"); 编译成功,无报错
  • TU_VERIFY_STATIC(0, "static verify failed\r\n"); 编译失败,有报错

示例

#include <stdio.h>
#include "stdint.h"
#include <stdbool.h>

#define TU_STRCAT(a, b) a##b             ///< concat without expand
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat

#define _TU_COUNTER_ __LINE__

#define TU_VERIFY_STATIC(const_expr, _mess) enum                     \
{
      
                                                                          \
    TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1 / (!!(const_expr)) \
}

typedef struct __attribute__((packed))
{
    
    
    uint8_t cmd_code;
    uint8_t reserved[6];
    uint16_t alloc_length;
    uint8_t control;
} scsi_read_format_capacity_t;
TU_VERIFY_STATIC(sizeof(scsi_read_format_capacity_t) == 10, "size is not correct");

TU_VERIFY_STATIC(1, "static verify successful\r\n");
TU_VERIFY_STATIC(0, "static verify failed\r\n");

int main(int argc, char *argv[])
{
    
    
    printf("hello tyustli\r\n");

    return 0;
}

结果打印

test.c:12:51: warning: division by zero [-Wdiv-by-zero]
   12 |     TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1 / (!!(const_expr)) \
      |                                                   ^
test.c:25:1: note: in expansion of macro ‘TU_VERIFY_STATIC’
   25 | TU_VERIFY_STATIC(0, "static verify failed\r\n");
      | ^~~~~~~~~~~~~~~~
test.c:12:16: error: enumerator value for ‘_verify_static_25’ is not an integer constant
   12 |     TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1 / (!!(const_expr)) \
      |                ^~~~~~~~~~~~~~~
test.c:5:25: note: in definition of macro ‘TU_STRCAT’
    5 | #define TU_STRCAT(a, b) a##b             ///< concat without expand
      |                         ^
test.c:12:5: note: in expansion of macro ‘TU_XSTRCAT’
   12 |     TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1 / (!!(const_expr)) \
      |     ^~~~~~~~~~
test.c:25:1: note: in expansion of macro ‘TU_VERIFY_STATIC’
   25 | TU_VERIFY_STATIC(0, "static verify failed\r\n");

解析

改宏主要利用了 enum 枚举成员必须是整数的特性

  • TU_XSTRCAT(_verify_static_, _TU_COUNTER_) 这一句宏是将 _verify_static___LINE__ 连接在一起,用于生成一个独一无二的名称,例如 _verify_static_15_verify_static_16
    • 在一个文件中,行数肯定是不会重复的,所以编译不会报错
    • 在多个文件中,行数会重复,由于该变量并未使用,枚举类型中的成员重名,并不会报错。
  • !!(const_expr) 条件 const_expr 进行两次逻辑非运算,得到 逻辑值 结果 0 或者 1。如果表达式 const_expr 的结果为 0 ,则得到 0 , 如果为非 0 值,则得到 1
  • 上一步得到一个逻辑 0 或者逻辑 1,用 1/1 不会报错, 1/0 编译会报错。

TU_XSTRCAT 为什么用两级?

如果直接用 TU_STRCAT(_verify_static_, _TU_COUNTER_),由于 ## 是用于宏参数的连接,则结果为 _verify_static__TU_COUNTER_
如果使用 TU_XSTRCAT(_verify_static_, _TU_COUNTER_) 则宏展开时,两个参数分别为 _verify_static_ _TU_COUNTER_。这两个参数又作为参数传递给 TU_STRCAT,所以连接的就是 _verify_static_真正的数字

猜你喜欢

转载自blog.csdn.net/tyustli/article/details/132009915