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

第三部分,类似 #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有何作用?

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

// ConsoleTest.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
using namespace std;
#define int double
void _tmain(int argc, _TCHAR* argv[])
    int iOne = 1;
    cout<<sizeof(iOne)<<endl;
    #pragma push_macro("int")
    #undef int
    int 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++中常用的预定义宏以及 宏定义中 # 和 ## 的区别第一部分,常见的预定义宏__FILE__ 源文件的名称 如XXX.cpp__LINE__ 代码在源文件中是第几行 __DATE__ 源文件完成日期如Aug 17 2011__TIME__ 源文件完成时间如19:31:13__TIME... #pragma 一般格式: #pragma Para,其Para为参数。 message参数,code_seg,#pragma once,#pragma hdrstop,#pragma resource, #pragma warning,#pragma comment,#pragma disable,#pragma data_seg, #pragma region ...... #pragma pop_macro("new") 它的作用就是将宏定义new压入栈并取消它的定义,如此一来new的本来含义便获得了恢复,使用完毕后将宏定义new弹出栈,恢复宏定义。 不过,仍有下面两个问题需 ...... #pragma pop_macro("new") 它的作用就是将宏定义new压入栈并取消它(指的是宏)的定义,如此一来,new的本来含义便获得了恢复,使用完毕后将宏定义new弹出栈,恢复宏定义。 不过,仍有 大家有没有想过,在vs2019的编译器上只要按下Ctrl+F5,一个test.c的源程序就能变成一个.exe的可执行程序,这其是如何通过编译产生的呢,本章就和大家一起把这其的知识和重点的预处理一起学习一下。 一、程序的翻译环境和运行环境 1.任何ANSI
C/C++宏定义的一些使用技巧 我在写代码的时候喜欢使用宏,不仅使代码看起来整洁,而且用好了还能极大的减轻编码的工作量,但是如果使用不当的话,出了问题查找起来就就非常的难了,下面的总结大部分是从网上看到的,也有一些是我自己在工作总结出来的。 宏使用的常见的基础问题 防止一个头文件被重复包含    #ifndef BODYDEF_H    #define...
很长一段时间在win下开发,把一些win下特有的宏和标准c++预定义宏混淆了。记录一下 参考链接:https://msdn.microsoft.com/zh-cn/library/b0084kay.aspx https://en.cppreference.com/w/cpp/preprocessor/replace Visual c + + 编译器预定义某些预处理器宏,具体取决于语言 ...
C:MSC就是Microsoft的C/C++编译器。 VER:Version的简写。 _MSC_VER的意思就是:Microsoft的C/C++编译器版本预定义宏。 http://baike.baidu.com/link?url=