C代码中的###用法

Posted Frey_Liu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C代码中的###用法相关的知识,希望对你有一定的参考价值。

C代码中的#、##用法

#和##基础

对于这两个语法的功能都比较简单,且都是在预处理阶段做一些工作 :

  • #主要是将宏参数转化为字符串
  • ##主要是将两个标识符拼接成一个标识符
    #include <stdio.h>
    #include <stdlib.h>
    //#的简单使用 
    #define STR(str) #str
    //##的简单使用
    #define  CMB(a,b) a##b
    
    int main(int argc, char *argv[]) 
    
        int CMB(uart,1) = 5;
        int CMB(uart,2) = 10;
    
        printf("#的简单使用:\\r\\n");
        printf("%s\\r\\n",STR(3.1415));
        printf("%s\\r\\n",STR(abcd));
    
        printf("##的简单使用:\\r\\n");
        printf("%d\\r\\n",uart1);    
        printf("%d\\r\\n",uart2);
    
        return 0;
    
    

    从结果上看来似乎#仅仅只是代替了字符串的双引号,而##却实现了标识符的拼接,这样就为编码标识符的处理上能够带来更多的可玩性。

#的用法

  1. 标识符的“字符串变量"
    “#”一般结合打印语句组合成一个宏定义,可以方便的打印相关信息,下面给个简单的实例就明白了。

    #include <stdio.h>
    #include <stdlib.h>
    
    //#打印调试 
    #define DebugLogExpr(Expr)     printf("%s : %d\\r\\n",#Expr, Expr);  
    
    //私有参数访问 
    int sFucntion(void)
    
        static int var = 10;
        return var;
     
    
    int main(int argc, char *argv[]) 
    
        int DebugVar = 50;
    
        DebugLogExpr(DebugVar);     //直接打印变量名和变量 
        DebugLogExpr(100/5);        //打印表达式及结果 
        DebugLogExpr(sFucntion());  //打印相关函数名及结果 
    
        return 1;
    
    


    这样的话就不需要总是采用双引号来单独书写,同时你还可以继续扩展构造更加灵活的宏。

  2. 结合##进行字符串拼接打印
    前面介绍了##进行标识符的拼接,那么实现拼接标识符转化为字符串看来很简单吧,于是你会编写了如下代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    //#的简单使用 
    #define STR(str) #str
    
    //##的简单使用
    #define  CMB(a,b) a##b
    
    #define STR_CON(str) STR(str)  //转换宏 
    
    int main(int argc, char *argv[]) 
    
        int CMB(uart,1) = 5;
    
        printf("%s\\r\\n",STR_CON(CMB(uart,1)));
    
        return 0;
    
    

    进行宏定义嵌套的情况,#或者##仅在当前宏有效,嵌套宏中不会再次展开,既然当前宏无法展开,那么我只能再加一级宏定义作为转换宏进行展开,看能不能解决该问题:

    首先进行第一层转换宏替换处理掉##拼接符得到str(uart1),然后进行字符串转换符的处理为uart1字符串打印输出,当然以后你会遇到一些复杂的,不过要诀就是宏替换只会处理当前的#或者##,否则就需要增加转换宏提前进行宏替换展开。
    所以采用##拼接出来的标识符想要打印输出的话,使用#进行转换是最直接、方便的。

##的用法

##拼接符的玩法有点多,甚至有些还比较绕,当然如果你游刃有余的话,这对于重构代码是一把“ 利器 ”。

  1. 在结构体定义中的妙用
    下面是很多开源代码中惯用的做法,相比常规的结构体定义法,确实省去很多重复的代码。
    #include <stdio.h>
    #include <stdlib.h>
    
    #define DF_STRUCT(name) typedef struct tag##name name;\\
                             struct tag##name
    
    DF_STRUCT(DevManage)
    
        int index;   //索引 
        int Access;  //权限
                      //...  
    ;
    
    int main(int argc, char *argv[]) 
    
       DevManage stDevManage;
    
       stDevManage.index  = 1;
       stDevManage.Access = 666;
    
        printf("Dev Index :%d\\n",stDevManage.index );
        printf("Dev Access:%d\\n",stDevManage.Access );
    
        return 1;
    
    
  2. 统一宏替换
    拼接标识符意味着符号的粒度更高,而这碎片化的符号进行有效的管理,就可以使得符号更加具有通用性和灵活性。
    其实这种思想跟我们代码模块话是同样的道理。
    来首先我们用一个两层拼接体验一下:
    #include <stdio.h>
    #include <stdlib.h>
    
    //假如这是stm32库中的宏 
    #define GPIO_Pin_0                 ((int)0x0001)  /*!< Pin 0 selected */
    #define GPIO_Pin_1                 ((int)0x0002)  /*!< Pin 1 selected */
    #define GPIO_Pin_2                 ((int)0x0004)  /*!< Pin 2 selected */
    #define GPIO_Pin_3                 ((int)0x0008)  /*!< Pin 3 selected */
    
    #define USART1              ((int *) 0x1000)
    #define USART2              ((int *) 0x2000)
    
    
    //拼接变量 
    #define UARTX 1
    
    //最终的组合标识符 
    #define UART1_CORE  USART1
    #define UART1_RX    GPIO_Pin_0
    #define UART1_TX    GPIO_Pin_1
    
    #define UART2_CORE  USART2
    #define UART2_RX    GPIO_Pin_2
    #define UART2_TX    GPIO_Pin_3
    
    //拼接过程 
    #define _UARTX_CORE(uartx)   UART##uartx##_CORE 
    #define UARTX_CORE(uartx)    _UARTX_CORE(uartx)
    
    
    #define _UARTX_RX(uartx)   UART##uartx##_RX
    #define UARTX_RX(uartx)    _UARTX_RX(uartx) 
    
    #define _UARTX_TX(uartx)   UART##uartx##_TX
    #define UARTX_TX(uartx)    _UARTX_TX(uartx)
    
    
    int main(int argc, char *argv[]) 
    
        //组合标识符的使用 
        printf("0x%x\\n",UARTX_CORE(UARTX));
        printf("0x%x\\n",UARTX_RX(UARTX));
        printf("0x%x\\n",UARTX_TX(UARTX));
    
        return 1;
    
    
    而在前面介绍##的基础知识提过,只要转换宏写得够多,你可以一层套一层,最终获得你想要的标识符,达到修改一个简单的宏即可替换一整套宏的效果。
    所以关键还是你要清晰的把拼接变量找出来,当然多个也是同样没有问题的,跟我们函数传递参数一样,不过这样也会增加整个替换的复杂度,合理利用即可。

以上是关于C代码中的###用法的主要内容,如果未能解决你的问题,请参考以下文章

c语言 switch的用法

比特位计数--C++ bitset 用法

C 语言数组 ( 指针数组用法 | 自我结束能力 )

c用法中的jstring到char *未转换为可打印格式

c语言sleep的用法

C#中 Vector的用法