C/C++宏中的#与##

宏中的#的功能是将其后面的宏参数进行字符串化操作(Stringizing operator),简单说就是在它引用的宏变量的左右各加上一个双引号。

如定义好#define STRING(x) #x之后,下面二条语句就等价。

char *pChar = "hello";

char *pChar = STRING(hello);

还有一个#@是加单引号(Charizing Operator)

#define makechar(x)  #@x

char ch = makechar(b);与char ch = ‘b‘;等价。

但有小问题要注意,宏中遇到#或##时就不会再展开宏中嵌套的宏了。什么意思了?比如使用char *pChar =STRING(__FILE__);虽然__FILE__本身也是一个宏,但编译器不会展开它,所以pChar将指向"__FILE__"而不是你要想的形如"D:\XXX.cpp"的源文件名称。因此要加一个中间转换宏,先将__FILE__解析成"D:\XXX.cpp"字符串。

定义如下所示二个宏:

#define _STRING(x) #x

#define STRING(x) _STRING(x)

再调用下面语句将输出带""的源文件路径

char* pChar = STRING(__FILE__);

printf("%s %s\n", pChar, __FILE__);

可以比较下STRING(__FILE__)与__FILE__的不同,前将带双引号,后一个没有双引号。

再讲下##的功能,它可以拼接符号(Token-pasting operator)。

MSDN上有个例子:

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

int token9 = 100;

再调用  paster(9);宏展开后token##n直接合并变成了token9。整个语句变成了

printf( "token""9"" = %d", token9 );

在C语言中字符串中的二个相连的双引号会被自动忽略,于是上句等同于

printf("token9 = %d", token9);。

即输出token9 = 100

有了上面的基础后再来看示例1

#define WIDEN2(x) L ## x

#define WIDEN(x) WIDEN2(x)

#define __WFILE__ WIDEN(__FILE__)

wchar_t *pwsz = __WFILE__;

第一个宏中的L是将ANSI字符串转化成unicode字符串。如:wchar_t *pStr = L"hello";

再来看wchar_t *pwsz = __WFILE__;

__WFILE__被首先展开成WIDEN(__FILE__),再展开成WIDEN2("__FILE__表示的字符串"),再拼接成 L"__FILE__表示的字符串" 即L"D:\XXX.cpp" 从而得到unicode字符串并取字符串地址赋值给pwsz指针。

在VC中_T(),TEXT ()也是用的这种技术。

在tchar.h头文件中可以找到:

#define _T(x)       __T(x)

#define __T(x)      L ## x

在winnt.h头文件中可以找到

#define TEXT(quote) __TEXT(quote)   // r_winnt

#define __TEXT(quote) L##quote      // r_winnt

因此不难理解为什么第三条语句会出错error C2065: ‘LszText‘ : undeclared identifier

wprintf(TEXT("%s %s\n"), _T("hello"), TEXT("hello"));

char szText[] = "hello";

wprintf(TEXT("%s %s\n"), _T(szText), TEXT(szText));

而将"hello"定义成宏后就能正确运行。

#define SZTEXT "hello"

wprintf(TEXT("%s %s\n"), _T(SZTEXT), TEXT(SZTEXT));

时间: 2024-10-29 19:05:33

C/C++宏中的#与##的相关文章

sas宏(3)宏,调试宏,创建带参数的宏,理解符号表(全局宏与局部宏解析),宏条件运算符,在宏中进行运算

宏类似于c中的函数,传入指定参数后执行,并且宏内部可以包含data步程序和条件运算符号. 宏变量只是小小的变量....(by the way作用也很大) 1:宏的基本语法 如何创建一个简单的宏并使用? %macro prtlast; proc print data=&syslast (obs=5); title "Listing of &syslast data set"; run; %mend; %prtlast /*不要加分号,加了有可能出错*/ 宏创建过程中做了什

Confluence 6 在你用户宏中使用参数

你可以为你的用户宏指定参数.这样的话,用户可以使用参数来决定 Confluence 页面的显示情况. 如何在 Confluence 页面中使用你的宏参数 当添加一个宏到 Confluence 页面中的时候,宏浏览器将会为每一个选择的宏显示输入字段,这个输入字段就是你需要指定的参数. 定义参数 在模板中的参数定义为: @param 参数的名称 一系列属性(可行). 格式: ## @param MYNAME:title=MY TITLE|type=MY TYPE|desc=MY DESCRIPTIO

宏中的逗号

很多地方看到使用一个宏 #define WIN_ID(_ID_)            WINID, 100 这中间的逗号是 其实是  逗号表达式 右侧表达式 宏里面还有一些其他的表符号表达式 优先级:*> +> => , #define f(x) x*x,x+x 表达式 x*x,x+x 根据逗号表达式的右结合性,它取x+x #define g(x) f(x)=x*x,x+x 如果是这样定义的话,等号高于逗号 f(x)的对应的是 x*x   g(x)根据逗号表达式对应的是 x+x

秀丸编辑器在宏中设置文本替换正则表达式

替换文本中的换行符号为其他符号,这里我需要将换行符号替换为逗号: 首先建立一个以".MAC"后缀的文件,如a.MAC; 其次在文件中保存如下内容: replaceall "[\r\n]",",", regular; endmacro; 之后再秀丸编辑器的菜单栏"Marco"->"Load record" 点击Browse选择刚才建立的文件,点击OK后. 用秀丸打开需要替换的文件,之后在编辑器菜单栏&q

2000行之宏中#和##的区别

#include<stdio.h> #define Fun(a,b) a##b int main() { x='H'; y='W'; printf("%s",Fun(x,y)); return; } #include<stdio.h> #define Var(x) var##x int main() { int Var(1)=1,Var(2)=2,Var(3)=3; printf("var1=%d\n",var1); printf("

宏定义中的#,##,...,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

C语言中宏定义使用方法详解

C语言中的宏替换详解 首先看一个问题: #include <stdio.h> #define    PRINT_CLINE()    printf("%d", ______) int main(void) { PRINT_CLINE(); PRINT_CLINE(); return 0; } 在横线处填上适当的代码,使得上面这段代码的输出为34. 我想一般人看到这个问题的时候头脑里都没有明确的思路来解答这个它.我看到这个问题的时候想出了各种办法来解答它,最终还是没有通过编译

【C++常识】C++中宏的使用

C/C++从编辑到生成目标文件的过程中,经历了预处理(#include.#if.#define).编译.汇编和链接这几个过程,宏替换就是出现在预处理中,宏替换时不做任何的语法检查.由于宏替换时上下文可能存在不同的情况,因此要求对宏替换过程中对存在的变量使用括号包起来,切为了避免歧义,尽量不要在宏中使用自增自减运算符. 一.宏中使用#以及## 说明:"#"将宏中的参数字符串化,"##"将2个token连接为1个 // 输出class的大小 #define OUT_CL

C中的预编译宏定义

文章来自 http://www.uml.org.cn/c++/200902104.asp 在将一个C源程序转换为可执行程序的过程中, 编译预处理是最初的步骤. 这一步骤是由预处理器(preprocessor)来完成的. 在源流程序被编译器处理之前, 预处理器首先对源程序中的"宏(macro)"进行处理. C初学者可能对预处理器没什么概念, 这是情有可原的: 一般的C编译器都将预处理, 汇编, 编译, 连接过程集成到一起了. 编译预处理往往在后台运行. 在有的C编译器中, 这些过程统统由