这样的话编译器会提示说,“L__FILE__”: 未声明的标识符。

这是为什么?

如果##后的参数本身也是一个宏的话,##会阻止这个宏的展开,也就是只替换一次。需要加一层中介完成代换,就想这样。

#define __WFILE3__(x) (L##x)
#define __WFILE2__(x) __WFILE3__(x)
#define __WFILE__  __WFILE2__(__FILE__)

wchar_t pszFilePath[]=__WFILE__;

当宏函数的定义中调用了另一个宏函数,预处理器会将其中所有可展开的宏展开。这样就可以了。

再看一个具有迷惑性的错误宏定义:

#define __WFILE1__(x) (L##x)

#define __WFILE__  __WFILE1__(__FILE__)

wchar_t pszFilePath[]=__WFILE__;

这样呢,编译器同样会报出L__FILE__未定义,也就是说L_FILE__不是一个字符串。

让我们一步一步看看预处理器是如何做的吧?

1.当预处理器到达wchar_t pszFilePath[]=__WFILE__;它发现宏定义,然后执行展开__WFILE1__( __FILE__ )

2.同时发现__FILE1__又是一个宏定义,那么展开(L##__FILE1__)

为什么预处理器没有展开__FILE1__呢,你可能觉得,自己已经添加了中间步骤。但实际上没有,我们单单看__WFILE1__( __FILE__ ),不关其他定义,你就会发现,这个宏定义根据前面的规则是绝对不会展开的,所以前面的__WFILE__根本没有起到中间代换的作用。

所以总结起来的话,从__FILE__第一次出现,必须要经过中间一层宏。中间一层宏是指__FILE__必须出现在宏声明中(宏的左侧),同时宏的定义(即宏定义右侧)也是一个宏。那么这个宏才能称为中间层。这个中间层才能起到展开__FILE__的作用。

下面看下个错误的字符串宏定义例子

#define SHOWLINENUMW3(x) (L##x)
#define SHOWLINENUMW2(x) SHOWLINENUMW3(#x)
#define SHOWLINENUMW(x)  SHOWLINENUMW2(x)
#define __WLINE__ SHOWLINENUMW(__LINE__)

#define __WFILE3__(x) (L##x)
#define __WFILE2__(x) __WFILE3__(x)
#define __WFILE__  __WFILE2__(__FILE__ )

#define __N__ (__WFILE__ __WLINE__)

TCHAR szFileName[]=__N__;

注意L##x是带括号的。编译器提示:项不会计算为接受 1 个参数的函数。

为什么会出错呢?那是因为对多个单独的字符串连接时,不能用括号括起来括起任意一个。当然单独一个可以。

wchar_t szTemp[]=(L"nihao"); //第一种 可以

wchar_t szTemp[]=(L"nihao") (L"tahao");//第二种 不可以。

wchar_t szTemp[]=L"nihao" L"woyehao";//第三种 可以

而前面给出的错误的例子经过宏替换这后就相当于第二种,所以编译器会报告错误。我们需要将(L##x)改成L##x才能正确运行。

所以正确的例子是:

#define SHOWLINENUMW3(x) L##x
#define SHOWLINENUMW2(x) SHOWLINENUMW3(#x)
#define SHOWLINENUMW(x)  SHOWLINENUMW2(x)
#define __WLINE__ SHOWLINENUMW(__LINE__)

#define __WFILE3__(x) L##x
#define __WFILE2__(x) __WFILE3__(x)
#define __WFILE__  __WFILE2__(__FILE__ )

#define __N__ (__WFILE__ __WLINE__)

TCHAR szFileName[]=__N__;

2: __VA_ARGS__

__VA_ARGS__好像是c99标准加进来的宏定义功能,可能用于不变参数宏

#define MY_PRINTF( x,...) printf( x, ##__VA_ARGS__ )

其中...表示可变参数列表,__VA_ARGS__则是表示前面的可变参数列表,其中##用于在没可变参数列表时去掉前面的逗号。编译器会识别出##,并去掉前面的逗号。

如果没有##:

#define MY_PRINTF( x,...) printf( x, __VA_ARGS__ )

MY_PRINTF( "Hello World" );

宏展开后:

printf( "Hello World", );

这样的编译器会抱怨警告,甚至编译不过。采用##之后就可以了。而且##本身也是连接符。

当然有时我们可以直接:

#define MY_PRINTF(...) printf(__VA_ARGS__)

此时就不需要##,因为前面没有逗号。

暂时总结自己知道的这么多的,以后再补充吧。

条件编译 #if #endif #if #elif #else #endif #ifdef #if define 的使用方法 引头文件#include<> 和#include““的区别
条件编译 #if #endif #if #elif #else #endif #ifdef #if define 的使用方法 引头文件#include<> 和#include““的区别
#define 定义宏 概念和函数的优缺点,使用条件 #undef 宏的副作用 宏使用时的“潜规则“
#define 定义宏 概念和函数的优缺点,使用条件 #undef 宏的副作用 宏使用时的“潜规则“
Dev-c++中将头文件和头文件函数分离,编译主函数跳出undefined reference to 的问题解决
Dev-c++中将头文件和头文件函数分离,编译主函数跳出undefined reference to 的问题解决
Effective C++条款 02:尽量以 const, enum, inline 替换 #define
Effective C++条款 02:尽量以 const, enum, inline 替换 #define
[-] .\Navicat-Cracker NavicatCrackerDlg.cpp:332 -3All patch solutions are suppressed. Patch abort!HI