宏定义中#和##的使用

1. #

#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号

1   #define WARN_IF(EXP) /
2   do{ if (EXP) /
3   fprintf(stderr, "Warning: " #EXP "/n"); } /
4   while(0)

那么实际使用中会出现下面所示的替换过程:

1 WARN_IF (divider == 0);

被替换为

1 do {
2   if (divider == 0)
3   fprintf(stderr, "Warning" "divider == 0" "/n");
4 } while(0);

这样每次divider(除数)为0的时候便会在标准错误流上输出一个提示信息。

2. ##

##被称为连接符(concatenator),用来将两个Token连接为一个Token,##符是把传递过来的参数当成字符串进行替代。

例如

1 #define PRINT( n ) printf( "token" #n " = %d", token##n )

PRINT(mine );

在编译时会被编译成

1 printf( "token" "mine" " = %d", tokenmine );

举例说明

例一:

 1 #include<cstdio>
 2 #include<climits>
 3 using namespace std;
 4 #define STR(s) #s
 5 #define CONS(a,b) int(a##e##b)
 6 int main()
 7 {
 8     printf(STR(vck)); // 输出字符串"vck"
 9     printf("%d\n",  CONS(2,3)); // 2e3 输出:2000
10  return 0;
11 }

例二:Canopen协议中对象字典和相关变量的关联

 1 /* A macro to initialize the data in client app.*/
 2 /* CO_Data structure */
 3 #define CANOPEN_NODE_DATA_INITIALIZER(NODE_PREFIX) { 4     /* Object dictionary*/ 5     & NODE_PREFIX ## _bDeviceNodeId,     /* bDeviceNodeId */ 6     NODE_PREFIX ## _objdict,             /* objdict  */ 7     NODE_PREFIX ## _PDO_status,          /* PDO_status */ 8     NULL,                                /* RxPDO_EventTimers */ 9     _RxPDO_EventTimers_Handler,          /* RxPDO_EventTimers_Handler */10     & NODE_PREFIX ## _firstIndex,        /* firstIndex */11     & NODE_PREFIX ## _lastIndex,         /* lastIndex */12     & NODE_PREFIX ## _ObjdictSize,       /* ObjdictSize */13     & NODE_PREFIX ## _iam_a_slave,       /* iam_a_slave */14     NODE_PREFIX ## _valueRangeTest,      /* valueRangeTest */15     16     /* SDO, structure s_transfer */17     {18           REPEAT_SDO_MAX_SIMULTANEOUS_TRANSFERS_TIMES(s_transfer_Initializer)19     },20     21     /* State machine*/22     Unknown_state,      /* nodeState */23     /* structure s_state_communication */24     {25         0,          /* csBoot_Up */26         0,          /* csSDO */27         0,          /* csEmergency */28         0,          /* csSYNC */29         0,          /* csHeartbeat */30         0,           /* csPDO */31         0           /* csLSS */32     },33     _initialisation,     /* initialisation */34     _preOperational,     /* preOperational */35     _operational,        /* operational */36     _stopped,            /* stopped */37     NULL,                /* NMT node reset callback */38     NULL,                /* NMT communications reset callback */39     40     /* NMT-heartbeat */41     & NODE_PREFIX ## _highestSubIndex_obj1016, /* ConsumerHeartbeatCount */42     NODE_PREFIX ## _obj1016,                   /* ConsumerHeartbeatEntries */43     NODE_PREFIX ## _heartBeatTimers,           /* ConsumerHeartBeatTimers  */44     & NODE_PREFIX ## _obj1017,                 /* ProducerHeartBeatTime */45     TIMER_NONE,                                /* ProducerHeartBeatTimer */46     _heartbeatError,           /* heartbeatError */47     48     {REPEAT_NMT_MAX_NODE_ID_TIMES(NMTable_Initializer)},49                                                    /* is  well initialized at "Unknown_state". Is it ok ? (FD)*/50     51     /* NMT-nodeguarding */52     TIMER_NONE,                                /* GuardTimeTimer */53     TIMER_NONE,                                /* LifeTimeTimer */54     _nodeguardError,           /* nodeguardError */55     & NODE_PREFIX ## _obj100C,                 /* GuardTime */56     & NODE_PREFIX ## _obj100D,                 /* LifeTimeFactor */57     {REPEAT_NMT_MAX_NODE_ID_TIMES(nodeGuardStatus_Initializer)},58     59     /* SYNC */60     TIMER_NONE,                                /* syncTimer */61     & NODE_PREFIX ## _obj1005,                 /* COB_ID_Sync */62     & NODE_PREFIX ## _obj1006,                 /* Sync_Cycle_Period */63     /*& NODE_PREFIX ## _obj1007, */            /* Sync_window_length */64     _post_sync,                 /* post_sync */65     _post_TPDO,                 /* post_TPDO */66     _post_SlaveBootup,            /* post_SlaveBootup */67   _post_SlaveStateChange,            /* post_SlaveStateChange */68     69     /* General */70     0,                                         /* toggle */71     NULL,                   /* canSend */72     NODE_PREFIX ## _scanIndexOD,                /* scanIndexOD */73     _storeODSubIndex,                /* storeODSubIndex */74     /* DCF concise */75     NULL,       /*dcf_odentry*/76     NULL,        /*dcf_cursor*/77     1,        /*dcf_entries_count*/78     0,        /* dcf_status*/79     0,      /* dcf_size */80     NULL,   /* dcf_data */81     82     /* EMCY */83     Error_free,                      /* error_state */84     sizeof(NODE_PREFIX ## _obj1003) / sizeof(NODE_PREFIX ## _obj1003[0]),      /* error_history_size */85     & NODE_PREFIX ## _highestSubIndex_obj1003,    /* error_number */86     & NODE_PREFIX ## _obj1003[0],    /* error_first_element */87     & NODE_PREFIX ## _obj1001,       /* error_register */88     & NODE_PREFIX ## _obj1014,       /* error_cobid */89     /* error_data: structure s_errors */90     {91     REPEAT_EMCY_MAX_ERRORS_TIMES(ERROR_DATA_INITIALIZER)92     },93     _post_emcy,              /* post_emcy */94     /* LSS */95     lss_Initializer96 }

宏定义中#和##的使用

时间: 2024-10-07 12:15:59

宏定义中#和##的使用的相关文章

宏定义中的#,##,...,do{}while(0),__VA_ARGS__

宏定义中的#,## 1.在一个预处理器宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组 #define syslog(a) fprintf(stderr,"Warning: " #a"\n"); 2.简单的说,"## "是一种分隔连接方式,它的作用是先分隔,然后进行强制连接 举列 -- 试比较下述几个宏定义的区别 #define A1(name, type)  type name_##type##_type 或 #define A

宏定义中使用do{}while(0)的好处 (转载)

宏定义中使用do{}while(0)的好处   #define MACRO_NAME(para) do{macro content}while(0) 的格式,总结了以下几个原因: 1,空的宏定义避免warning: #define foo() do{}while(0) 2,存在一个独立的block,可以用来进行变量定义,进行比较复杂的实现. 3,如果出现在判断语句过后的宏,这样可以保证作为一个整体来是实现: #define foo(x) /action1(); /action2(); 在以下情况

宏定义中##和#的作用

解释1 : 定义中##和#的作用内核中有很多的宏定义,在宏定义define中经常看到两个字符串##和#,这里把它的用法做一下说明:1. ####是一个连接符号,用于把参数连在一起例如:> #define FOO(arg) my##arg则> FOO(abc)相当于 myabc2.#:是"字符串化"的意思.出现在宏定义中的#是把跟在后面的参数转换成一个字符串例如:> #define STRCPY(dst, src) strcpy(dst, #src)则> STRC

C宏定义中的 #,##,#@

宏定义中会出现#xxx ,A###B,以及微软独自特有的#@xxx.分别解释. 1 define SB(x) #x 它的作用是把输入的东西转换为字符串 string str = SB(123); 2 define BB(x) UXX##x 这个是个符号连接的作用,把UXX(随意的跟符号x连接成一个新的符号,这里说的符号就是变量的意思 int BB(1); U1 = 100; 3 define CB(x) #@x 作用会是把x的最后一个字符转换成字符,这个是Windows独有的. char b =

#和##在宏定义中使用问题

转自:http://www.linuxidc.com/Linux/2014-06/102925.htm 有一道经典的C语言问题,关于宏定义中#和##符号的使用和宏定义展开问题 程序如下: #include <stdio.h>#define f(a,b) a##b#define g(a)  #a#define h(a) g(a) int main(){        printf("%s\n", h(f(1,2)));        printf("%s\n&quo

do{}while(0)在宏定义中作用

在开源代码中看到,宏定义经常这样用 #define some() do { do_somt_thing(); } while (0) 为什么这样用? 可以试一下,假如一个普通宏定义 #define some(x) Fun1(x);Fun2(x) if(condition) some(x); 变为 if(condition) Fun1(x); Fun2(x); 这样直接加个花括号不久行了,为什么还用do......while()?假如加上花括号 #define some(x) {Fun1(x);F

C 语言宏定义中使用do...while(0)

最近看到C语言的项目中在宏定义中使用了do...while(0),感到是个知识点,特来总结. 先看这句话:do{...}while(0)在C中是唯一的构造程序,让你定义的宏总是以相同的方式工作,这样不管怎么使用宏(尤其在没有用大括号包围调用宏的语句),宏后面的分号也是相同的效果.这句话的意思是说,在宏定义中使用do...while(0)包含的所有语句是一个代码块,不会受到{}:的影响. 看一个例子: #include <stdio.h> #include <stdlib.h> #d

do...while(0)在宏定义中的巧妙用法

大家都知道,do-while(condition)可以表示循环,但你有没有遇到在一些宏定义中可以不用循环的地方,也用到了 do-while.比如: #define DELETE_POINTER(p) do { if(NULL != p) delete p; p = NULL; }while(0) 这时,do-while(0)的功能就不仅仅是循环了,这是do..while(0)的一种巧妙用法.它有以下几种功能: 1.在后面要加分号,使调用如同函数:调用如下: int* p = new int(5)

define宏定义中的#,##,@#及\符号

define宏定义中的#,##,@#及\符号 在#define中,标准只定义了#和##两种操作.#用来把参数转换成字符串,##则用来连接两个前后两个参数,把它们变成一个字符串. 1.# (stringizing)字符串化操作符.其作用是:将宏定义中的传入参数名转换成用一对双引号括起来参数名字符串.其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前. 如: #define example(instr) printf("the input string is:\t%s\n",#