专注于Windows编程

C,C++宏中#与##的讲解

文中__FILE__与示例1可以参见《使用ANSI C and Microsoft 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));

注:由于VC6.0默认是ANSI编码,因此要先设置成unicode编码,在project菜单中选择Setting,再在C/C++标签对话框中的Category中选择Preprocessor。再地Preprocessor definitions编辑框中将_MBCS去掉,加上_UNICODE,UNICODE。

更多内容可以查考MSDN上对Preprocessor Operators的讲解。

转载请标明出处,原文地址:http://www.cnblogs.com/morewindows/archive/2011/08/18/2144112.html

C,C++宏中#与##的讲解[转]的更多相关文章

  1. C/C++宏中#与##的讲解

    http://www.cnblogs.com/morewindows/archive/2011/08/18/2144112.html

  2. C/C++ 宏中的 #、#@、##的作用

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

  3. UML在需求分析与系统设计中之实战讲解

    UML在需求分析与系统设计中之实战讲解(完整UML图形演示) 小序: 从学生时代就接触到UML,几年的工作中也没少使用,各种图形的概念.图形的元素和属性,以及图形的画法都不能说不熟悉.但是怎样在实际中 ...

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

    你可以为你的用户宏指定参数.这样的话,用户可以使用参数来决定 Confluence 页面的显示情况. 如何在 Confluence 页面中使用你的宏参数 当添加一个宏到 Confluence 页面中的 ...

  5. C/C++ 的宏中#和##的作用和展开

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

  6. maya 2014帮助手册中 三维概念讲解

    maya 2014 帮助手册中   三维概念讲解 多边形简介 三个或更多的边,   顶点    边    面  组成 经常使用三边形或四边形来建模   n边形不常用 单个多边形称为面   多个面连接到 ...

  7. C函数和宏中的可变参数

    一:调用惯例 函数的调用方和被调用方对函数如何调用应该有统一的理解,否则函数就无法正确调用.比如foo(int n, int m),调用方如果认为压栈顺序是m,n,而foo认为压栈顺序是n, m,那么 ...

  8. React中key的讲解

    通过阅读React的文档我们知道React这个框架的核心思想是,将页面分割成一个个组件,一个组件还可能嵌套更小的组件,每个组件有自己的数据(属性/状态);当某个组件的数据发生变化时,更新该组件部分的视 ...

  9. cocos2dx中CC_CALLBACK_1等宏中this指针实际指向

    首先看代码,我在Helloworld中添加两个函数. void HelloWorld::addTarget(){ Size visibleSize = Director::getInstance()- ...

随机推荐

  1. 20145236 《Java程序设计》实验二实验报告

    北京电子科技学院(BESTI)实验报告 课程:Java程序设计 班级:1452 指导教师:娄嘉鹏 实验日期:2016.04.08 实验名称: Java面向对象程序设计 实验内容: 初步掌握单元测试和T ...

  2. c#和数据库技术基础之程序设计集散地-数据库

    数据库,不明觉厉,今天我们就来数据库的神秘面纱 1.使用数据库的必要性 随着互联网技术的高速发展,截止到2013年我国网民的数量已接近6亿,网民数量的增长同事带动网上购物,微博,网络视频等新产业的发展 ...

  3. JVM优化之调整大内存分页(LargePage)

    转自:http://cjjwzs.iteye.com/blog/1059381 本文将从内存分页的原理,如何调整分页大小两节内容,向你阐述LargePage对JVM的性能有何提升作用,并在文末点明了大 ...

  4. 读取DBF文件的部分代码

    private void BtnOpenInitial_Click(object sender, EventArgs e) { OpenFileDialog file = new OpenFileDi ...

  5. 在eclipse导入项目的步骤【转】

    1. Import 2. Next 3. 确定  选中copy projects into workspace    Finish 这样项目就导入进来了. 4.导入jar包 Configure Bui ...

  6. HTML5+CSS3学习目录

       目录 第YI章 Web开发新时代 第2章 从HTML.XHTML到HTML5 第3章 创建HTML5文档 第4章 实战HTML5表单 第5章 实战HTML5画布 第6章 HTML5音频与视频 第 ...

  7. js克隆

    一.有什么用 不破坏原对象的属性 引入一些概念~ 原始数据类型(5种):undefined.null.number.string.boolean 引用数据类型(1种,也叫复合数据类型):object ...

  8. wScratchPad 实现刮刮卡效果

    插件网址http://wscratchpad.websanova.com/

  9. C# 轉義字符

    转义字符 意义 ASCII码值(十进制) \a 响铃(BEL) 007 \b 退格(BS) ,将当前位置移到前一列 008 \f 换页(FF),将当前位置移到下页开头 012 \n 换行(LF) ,将 ...

  10. 从协议VersionedProtocol开始3——ClientProtocol、DatanodeProtocol、NamenodeProtocol、RefreshAuthorizationPolicyProtocol、RefreshUserMappingsProtocol

    1.ClientProtocol这个玩意的版本号是61L:DatanodeProtocol 是26L:NamenodeProtocol是 3L;RefreshAuthorizationPolicyPr ...