• ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别

    • 第一部分,常见的预定义宏
    • 第二部分,# 和 ## 再宏定义中的使用说明
    • 第三部分,类似 #pragma push_macro(“new”) 的使用说明

ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别

第一部分,常见的预定义宏

__FILE__       源文件的名称  如XXX.cpp
__LINE__       代码在源文件中是第几行
__DATE__      源文件完成日期如Aug 17 2011
__TIME__       源文件完成时间如19:31:13
__TIMESTAMP__ 源文件完成日期时间如Wed Aug 17 19:27:36 2011

如分配内存函数malloc()的一个版本就使用了上面的宏

#define   malloc(s)  _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)

另外可以在程序中使用__FILE____LINE__来确定是哪个文件哪一行出错:

     char *pszFileName = (char*)malloc(MAX_PATH * sizeof(char));if (pszFileName == NULL)printf("Error in %s %d\n",  __FILE__, __LINE__);

当然实际程序中大多用__FILE__和__LINE__快速定位错误后不会直接输出,而是通过另一程序来将这些信息以EMAIL形式反馈给开发人员。

__FILE__可以方便的转化成wchar_t类型,MSDN就有这个例子:

#define WIDEN2(x) L ## x#define WIDEN(x) WIDEN2(x)#define __WFILE__ WIDEN(__FILE__)wchar_t *pwsz = __WFILE__;

第二部分,# 和 ## 再宏定义中的使用说明

文中__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)  #@xchar 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的讲解。

第三部分,类似 #pragma push_macro(“new”) 的使用说明

在三方库源码中,我们经常看到这样的代码:

#pragma push_macro("new")#undef new// do something with new......#pragma pop_macro("new")

它的作用就是将宏定义new压入栈并取消它(指的是宏)的定义,如此一来,new的本来含义便获得了恢复,使用完毕后将宏定义new弹出栈,恢复宏定义。

不过,仍有下面两个问题需要回答。

1)宏定义名不会与关键字new冲突吗?

2)宏定义new有何作用?

问题1

宏定义名若与保留的关键字相同,编译器并不会提示错误,而是用最新定义的宏定义代替关键字发挥作用。下面是一个例子,定义了宏int。例程能顺利通过编译链接,其运行结果为8,4,8,与预期相同。

// ConsoleTest.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <iostream>
using namespace std;
#define int doublevoid _tmain(int argc, _TCHAR* argv[])
{int iOne = 1;cout<<sizeof(iOne)<<endl;#pragma push_macro("int")#undef intint iTwo = 2;cout<<sizeof(iTwo)<<endl;#pragma pop_macro("int")int iSecond=2;cout<<sizeof(iSecond)<<endl;system("pause");
}

解析:运行结果为8 ,4,8

宏定义,如#define PI 3.1415926 把程序中出现的PI全部换成3.1415926

#define int double   该句话表明,把程序中出现int的地方全部替换为double ,
(int iOne = 1;cout<<sizeof(iOne)<<endl;相当于iOne为double类型,所以输出8)
#pragma push_macro("int")#undef intint iTwo = 2;cout<<sizeof(iTwo)<<endl;#pragma pop_macro("int")

上面几句的意思是,将将宏定义int压入栈并取消它(指的是宏)的定义,如此一来,int的本来含义便获得了恢复,即int仍代表int。使用完毕后将宏定义int弹出栈,恢复宏定义即int代表double。

转载自:
1、https://blog.csdn.net/MoreWindows/article/details/6697488
2、https://blog.csdn.net/ivan_ljf/article/details/8787189
感谢优秀博主的分享。

ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别相关推荐

  1. java中常用的包、类、以及包中常用的类、方法、属性----sql和text\swing

    java中常用的包.类.以及包中常用的类.方法.属性 常用的包 java.io.*; java.util.*; java.lang.*; java.sql.*; java.text.*; java.a ...

  2. CMake 常用的预定义变量

    CMake 常用的预定义变量 PROJECT_NAME : 通过 project() 指定项目名称 PROJECT_SOURCE_DIR : 工程的根目录 PROJECT_BINARY_DIR : 执 ...

  3. cmake学习笔记(2)--CMake常用的预定义变量

    cmake常用的预定义变量不多,根据经验掌握如下几个就基本上够用了: PROJECT_NAME : 通过 project() 指定项目名称 PROJECT_SOURCE_DIR : 工程的根目录 PR ...

  4. otn系统中常用的电层_夏季温室大棚生产中常用的降温系统

    在炎热的夏季温室大棚中常用的降温技术有通风降温.遮阳降温.蒸发降温等降温技术.在实际应用中,由于不同的降温技术其降温原理不同,应用特点和适用范围也不同,存在一定的局限性和不足,仅采用某一种降温技术很难 ...

  5. Linux中常用的文件目录,Linux学习笔记2——Linux中常用文件目录操作命令

    ls 显示文件和目录列表 -l 列出文件的详细信息 -a 列出当前目录所有文件,包含隐藏文件 mkdir 创建目录 -p 父目录不存在情况下先生成父目录 cd 切换目录 touch 生成一个空文件 e ...

  6. 计算机技术中常用的术语CAE是指_,计算机技术中常用的术语CAE是指______。A:计算机辅助设计B:计算机辅助制造C:计算机辅助工程D:计...

    计算机技术中常用的术语CAE是指______.A:计算机辅助设计B:计算机辅助制造C:计算机辅助工程D:计 更多相关问题 土的极限平衡条件,就是土在极限平衡状态下,土中的主应力与土的抗剪强度参数之间的 ...

  7. 【Unity3D】资源文件 ① ( Unity 中常用的文件类型 | Unity 文件操作 | 文件系统中查看文件 | 添加文件 | 删除文件 | 导入文件 | 复制文件 | 缩略图显示 )

    文章目录 一.Unity 中常用的文件类型 二.Unity 文件操作 1.文件系统中查看文件 2.添加目录 / 文件 3.删除目录 / 文件 4.导入资源 5.复制资源 6.缩略图显示 7.meta ...

  8. c语言中常用的输入输出函数有哪些,C语言中常用的输入和输出函数

    C语言中常用的输入和输出函数 2020年03月11日 | 萬仟网IT编程 | 我要评论 1. scanf()函数 (Scan Format) + 函数原型: + 函数作用:从标准输入流 stdin ( ...

  9. 软件中常用的反义词组

    软件中常用的反义词组 add / remove       begin / end        create / destroy insert / delete       first / last ...

最新文章

  1. 类脑计算的一大突破 BrainScaleS-2
  2. python怎么读取txt文件内容然后保存到excel-Python实现读取txt文件并转换为excel的方法示例...
  3. anaconda powershell prompt 启动vscode_记一个VS Code终端显示问题的较完美解决
  4. 本地连接 阿里云 window 服务器mysql 总是2003
  5. HDU多校1 - 6959 zoto(莫队+树状数组/值域分块)
  6. MFC ListCtrl和IP控件的使用杂记
  7. RSS阅读器使用:ROME,Spring MVC,嵌入式Jetty
  8. mysql 停止服务内存_服务器莫名的内存高占用 导致 MySQL 停止运行问题
  9. 生产环境频繁内存溢出,原来就是因为这个“String类”
  10. php 结构和函数 区别吗,php的语言结构和函数的区别
  11. 2013汇总计算 广联达gcl_Revit软件与广联达软件两者的区别?哪个好?
  12. Vi的多文件间的复制和文本替换
  13. JVM系列一:JVM内存组成及分配
  14. python自动检测网站_Web全自动化测试Python + Pytest+Selenium+ Saucelabs 转
  15. 上海计算机二级vb题目,上海计算机二级VB试题(卷).doc
  16. matlab圆孔孔壁应力集中,matlab 有限元分析平面问题的小孔应力集中问题的程序 - 下载 - 搜珍网...
  17. oracle数据库书籍mobi,Oracle Database 12c PL/SQL开发指南(第7版) pdf epub mobi txt 下载...
  18. 【积水成渊-逐步定制自己的Emacs神器】4:Emacs自动补全
  19. Spring Security安全框架
  20. gitbook 安装使用

热门文章

  1. 将list中的元素按照属性分类成树状的map
  2. Bash 入门教程10-处理用户输入
  3. MySQL学习笔记_关于MySQL的字符类型VARCHAR长度知识总结
  4. Kaggle-自行车租赁人数预测
  5. ORA-00972: identifier is too long问题解决
  6. stm32时钟树_先学STM8,还是学STM32?
  7. 23根火柴游戏 c语言,23 根火柴游戏
  8. webstrom中打包的详细_webpack打包体积优化
  9. php transfer-encoding: chunked,php – 使用chunked transfer encoding和gzip
  10. 求n的阶乘的算法框图_算法|从阶乘计算看递归算法