definir definición de macro #, ##, @ # y / Símbolo

. 1 , ( stringizing ) cadena del operador . Su función es: el nombre del parámetro para convertir las definiciones de macro entrantes en un par de comillas dobles parámetro de cadena de nombre. Sólo se puede utilizar para definiciones de macro para el parámetro de entrada, y debe colocarse antes del nombre del parámetro en la definición de la macro.

Tales como:

ejemplo #define (INSTR) printf ( "la cadena de entrada es: / t% s / n", # INSTR)

#define example1 (INSTR) #instr

Cuando se utiliza esta macro definiciones:

Ejemplo (ABC) ; se ampliará a en tiempo de compilación: el printf ( "La cadena de entrada es: / T% S / n-", "ABC");

STR = example1 String (ABC) ; a la exposición: Cadena STR = "ABC" ;

nota:

espacios de tratamiento

Una . No haga caso de espacios traseros nombre del parámetro de entrada frontal y posterior.

   Tales como: STR = example1 (ABC) ; se extenderá a  STR = "ABC" ;

B. Cuando hay un entrante espacios entre el nombre del parámetro, el compilador se conectará automáticamente a las respectivas sub-cadenas, cada una subcadena utilizando sólo conectar con un espacio, un espacio extra que ignoraba.

   Tales como: str = exapme (abc def)  ; que se extenderá a  STR = "ABC DEF" ;

 

2 , ##  ( token-pegar ) operador símbolo concatenación

Una definición macro: nombre del parámetro, es decir, los parámetros, tales como SUM #define (a, b) (a + b) ; los unos y b representantes son el símbolo de un parámetro, es decir, parámetros formales.

## y una pluralidad de papel en forma de aspirado en una definición de macro de parámetro real nombre del parámetro.

Tales como:

#define exampleNum (n) num ## n

int num9 = 9;

uso:

int num = exampleNum (9);  se extenderá a  int num = num9;

nota:

1. Cuando un ## parámetro de conexión, ## espacios antes y después de opcional.

Tales como: #define exampleNum (n) num ##  n corresponde  #define exampleNum (n) num ## n

2. El nombre del parámetro real después de la conexión, tenga en cuenta el nombre del parámetro real o las macros presentes compilador

// preprocessor_token_pasting.cpp

#include <stdio.h>

#define paster( n ) printf_s( "token" #n " = %d", token##n )

int token9 = 9;

 

int main()

{

   paster(9);

}

运行结果:

token9 = 9

 

另外,如果##后的参数本身也是一个宏的话,##会阻止这个宏的展开

    #define STRCPY(a, b)    strcpy(a ## _p, #b)
    int main()
    {
        char var1_p[20];
        char var2_p[30];
        strcpy(var1_p, "aaaa");
        strcpy(var2_p, "bbbb");
        STRCPY(var1, var2);
        STRCPY(var2, var1);
        printf("var1 = %s/n", var1_p);
        printf("var2 = %s/n", var2_p);
        return 0;

        /* 注意这里 */
        STRCPY(STRCPY(var1,var2),var2);
        /* 这里是否会展开为: strcpy(strcpy(var1_p,"var2")_p,"var2“)?
         * 答案是否定的:
         * 展开结果将是:  strcpy(STRCPY(var1,var2)_p,"var2")
         * ## 阻止了参数的宏展开!
         * 如果宏定义里没有用到 # 和 ##, 宏将会完全展开
         */
    }  

 

 

3@# charizing字符化操作符

只能用于有传入参数的宏定义中且必须置于宏定义体中的参数名前。作用将传的单字符参数名转换成字符以一对单引用括起来

#define makechar(x)  #@x

a = makechar(b);

展开后变成了:

a= 'b';

 

4行继续操作符

当定义的宏不能用一行表达完整时,可以用"/"表示下一行继续此宏的定义。

另:关于其他网友对##和#的补充



1. 简单的说,“##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接。



   其中,分隔的作用类似于空格。我们知道在普通的宏定义中,预处理器一般把空格

   解释成分段标志,对于每一段和前面比较,相同的就被替换。但是这样做的结果是,

   被替换段之间存在一些空格。如果我们不希望出现这些空格,就可以通过添加一些

   ##来替代空格。



   另外一些分隔标志是,包括操作符,比如 +, -, *, /, [,], ...,所以尽管下面的

   宏定义没有空格,但是依然表达有意义的定义: define add(a, b)  a+b



   而其强制连接的作用是,去掉和前面的字符串之间的空格,而把两者连接起来。





2. 举列 -- 试比较下述几个宏定义的区别



   #define A1(name, type)  type name_##type##_type 或

   #define A2(name, type)  type name##_##type##_type



   A1(a1, int);  /* 等价于: int name_int_type; */

   A2(a1, int);  /* 等价于: int a1_int_type;   */



   解释:

        1) 在第一个宏定义中,"name"和第一个"_"之间,以及第2个"_"和第二个

   "type"之间没有被分隔,所以预处理器会把name_##type##_type解释成3段:

   “name_”、“type”、以及“_type”,这中间只有“type”是在宏前面出现过

    的,所以它可以被宏替换。



        2) 而在第二个宏定义中,“name”和第一个“_”之间也被分隔了,所以

   预处理器会把name##_##type##_type解释成4段:“name”、“_”、“type”

   以及“_type”,这其间,就有两个可以被宏替换了。



        3) A1和A2的定义也可以如下:

           #define A1(name, type)  type name_  ##type ##_type  

                                      <##前面随意加上一些空格>

           #define A2(name, type)  type name ##_ ##type ##_type



    结果是## 会把前面的空格去掉完成强连接,得到和上面结果相同的宏定义



3. 其他相关 -- 单独的一个 #



   至于单独一个#,则表示 对这个变量替换后,再加双引号引起来。比如



      #define  __stringify_1(x)   #x

那么

      __stringify_1(Linux)   <==>  "linux"



所以,对于MODULE_DEVICE_TABLE



     1) #define MODULE_DEVICE_TABLE(type,name)                        

             MODULE_GENERIC_TABLE(type##_device,name)

     2) #define MODULE_GENERIC_TABLE(gtype,name)                      

             extern const struct gtype##_id __mod_##gtype##_table     

             __attribute__ ((unused, alias(__stringify(name))))



得到  

      MODULE_DEVICE_TABLE(usb, products)  

                             /*notes: struct usb_device_id products; */

 <==> MODULE_GENERIC_TABLE(usb_device,products)

 <==> extern const struct usb_device_id __mod_usb_device_table     

             __attribute__ ((unused, alias("products")))   



注意到alias attribute需要一个双引号,所以在这里使用了__stringify(name)来

给name加上双引号。另外,还注意到一个外部变量"__mod_usb_device_table"被alias

到了本驱动专用的由用户自定义的变量products<usb_device_id类型>。这个外部变量

是如何使用的,更多的信息请参看《probe()过程分析》。



4. 分析方法和验证方式 -- 编写一个简单的C程序



   用宏定义一个变量,同时用直接方式定义一个相同的变量,编译报告重复定义;

   用宏定义一个变量,直接使用该宏定义的变量名称,编译通过且运行结果正确;

   使用printf打印字符串数据。printf("token macro is %s", __stringify_1(a1));

发布了18 篇原创文章 · 获赞 86 · 访问量 16万+

Supongo que te gusta

Origin blog.csdn.net/u013178472/article/details/72235688
Recomendado
Clasificación