宏定义中出现两个#是怎么个用法
一个C文档中的一个宏定义比较复杂,如下。其中多处出现##。这个是什么意思啊?
#define _COMPARE_TEMPLATE(MXC) \ Pair* compare_##MXC (Pair* pairs_iterator, \ const TYPEOF_##MXC * L1_pt, \ const TYPEOF_##MXC * L2_pt, \ int K1, int K2, int ND, float thresh) \ { \ int k1, k2 ; \ const PROMOTE_##MXC maxval = MAXVAL_##MXC ; \ for(k1 = 0 ; k1 < K1 ; ++k1, L1_pt += ND ) { \ \ PROMOTE_##MXC best = maxval ; \ PROMOTE_##MXC second_best = maxval ; \ int bestk = -1 ; \ \ /* For each point P2[k2] in the second image... */ \ for(k2 = 0 ; k2 < K2 ; ++k2, L2_pt += ND) { \ \ int bin ; \ PROMOTE_##MXC acc = 0 ; \ for(bin = 0 ; bin < ND ; ++bin) { \ PROMOTE_##MXC delta = \ ((PROMOTE_##MXC) L1_pt[bin]) - \ ((PROMOTE_##MXC) L2_pt[bin]) ; \ acc += delta*delta ; \ } \ \ /* Filter the best and second best matching point. */ \ if(acc < best) { \ second_best = best ; \ best = acc ; \ bestk = k2 ; \ } else if(acc < second_best) { \ second_best = acc ; \ } \ } \ \ L2_pt -= ND*K2 ; \ \ /* Lowe's method: accept the match only if unique. */ \ if(thresh * (float) best <= (float) second_best && \ bestk != -1) { \ pairs_iterator->k1 = k1 ; \ pairs_iterator->k2 = bestk ; \ pairs_iterator->score = best ; \ pairs_iterator++ ; \ } \ } \ \ return pairs_iterator ; \ } \_COMPARE_TEMPLATE( mxDOUBLE_CLASS )_COMPARE_TEMPLATE( mxSINGLE_CLASS )_COMPARE_TEMPLATE( mxINT8_CLASS )_COMPARE_TEMPLATE( mxUINT8_CLASS )
#include <iostream>using namespace std;#define X "abc"##"def" // 将abc和def连起来int main(void){ cout << X << endl; // 输出abcdef return 0;}
[解决办法]
#的功能是将其后面的宏参数进行字符串化操作
##用来将多个Token连接为一个Token
[解决办法]
#与##在宏定义中的--宏展开
#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))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)
return 0;
}
宏展开时:
如果宏定义以#开头,不展开参数,直接替换。
故g(f(1,2))--->#f(1,2)--->"f(1,2)";
如果宏定义不以#开头,展开参数,直接替换,由外层向里层,如果碰到的是#开头的宏,不继续往里层展开,往外层展开。
由外层向里层,如果碰到的是以非#开头的宏,继续往里层走,直至最里层,开始一层层往外层展开。
故h(f(1,2))--->h(12)--->g(12)---->#12----->"12"。
PS:
##在宏中定义,是字符连接符
如a##b##c 等同于 "abc"
#在宏开头出现,是表示宏展开的方式不同
#a 等同于"a"
#abc 等同于 "abc"
复杂的:
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
char a = 'a';
cout<<g(a)<<endl; // a
cout<<g(g(a))<<endl; // a
printf("%s\n", h(f(1,2))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)
printf("%s\n", g(h(f(1,2)))); // h(f(1,2))
printf("%s\n", h(g(f(1,2)))); // "f(1,2)"
printf("%s\n", h(h(f(1,2)))); // "12"
system("pause");
return 0;
}
预处理后的:(在编译选项中添加/EP /P后编译生成的.i文件)
int main()
{
char a = 'a';
cout<<"a"<<endl;
cout<<"g(a)"<<endl;
printf("%s\n", "12");
printf("%s\n", "f(1,2)");
printf("%s\n", "h(f(1,2))");
printf("%s\n", "\"f(1,2)\"");
printf("%s\n", "\"12\"");
system("pause");
return 0;
}
---------------------------------------------------
宏解析
1. ##操作符
##操作符它的作用是在替代表中将其前后的参数连接成为一个预处理符号,它不能出现于宏替代表的开端和末尾。
例:
#define concat(s,t) s##t
#define AAA ABC
concat(A, AA)
将被替换成
ABC
2. 重新扫描和替换
在替换列表中的所有参数替换过之后,预处理器将对结果token序列重新扫描以便对其中的宏再次替换。
当正在替换的宏在其替换列表中发现自身时,就不再对其进行替换。今儿,在任何正在嵌套替换的宏的替换过程中遇到正被替换的宏就对其不再进行替换(防止递归)。
例:
#define ROOT AAA CCC
#define AAA ROOT
ROOT
将被替换成
ROOT CCC
[解决办法]
Token-Pasting Operator (##)
The double-number-sign or “token-pasting” operator (##), which is sometimes called the “merging” operator, is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token and therefore cannot be the first or last token in the macro definition.
If a formal parameter in a macro definition is preceded or followed by the token-pasting operator, the formal parameter is immediately replaced by the unexpanded actual argument. Macro expansion is not performed on the argument prior to replacement.
Then, each occurrence of the token-pasting operator in token-string is removed, and the tokens preceding and following it are concatenated. The resulting token must be a valid token. If it is, the token is scanned for possible replacement if it represents a macro name. The identifier represents the name by which the concatenated tokens will be known in the program before replacement. Each token represents a token defined elsewhere, either within the program or on the compiler command line. White space preceding or following the operator is optional.
This example illustrates use of both the stringizing and token-pasting operators in specifying program output:
#define paster( n ) printf( "token" #n " = %d", token##n )
int token9 = 9;
If a macro is called with a numeric argument like
paster( 9 );
the macro yields
printf( "token" "9" " = %d", token9 );
which becomes
printf( "token9 = %d", token9 );