宏定义污染的解决方法。

来源:互联网 发布:淘宝首页模板免费下载 编辑:程序博客网 时间:2024/05/21 15:49

问题:

提要:
mfc工程调用另一个基本c++工程出错(windows宏定义污染导致<L_TYPE_raw>错误)
include windows.h 后STL的max/min函数会出错(尤其是一些类的成员函数)。

我用基本的C++配合STL写了一个库,编译成静态库lib。

又在同一个工作空间里面建立了个win32 console的工程,调用这个lib,一切正常。
然后我想加个界面,又建立了个基于对话框的mfc工程,用一样的方法include静态库工程的头文件,居然说我原来那个工程的文件语法有错,而且报的很奇怪,例如:

C/C++ code
?
1
2
3
4
5
6
7
8
9
10
#include ...
class Operation
{
public:
    enum kind_t{NONE=0,ADD,DELETE,REVERSE};
    kind_t kind;
    Node::pointer_t from,to;
public:
...
};

它说我enum的那一行在“)”前面缺少“}”。
2>d:\my program\projects\bayesian\bayesian\operation.h(12) : error C2143: 语法错误 : 缺少“}”(在“(”的前面)
2>d:\my program\projects\bayesian\bayesian\operation.h(12) : error C2059: 语法错误 : “<L_TYPE_raw>”
2>d:\my program\projects\bayesian\bayesian\operation.h(12) : error C2143: 语法错误 : 缺少“;”(在“}”的前面)
2>d:\my program\projects\bayesian\bayesian\operation.h(12) : error C2238: 意外的标记位于“;”之前


原因:

一开始怀疑是头文件顺序的问题,后来发现不是。

经过反复测试后发现,这其实是windows.h中的宏定义污染导致的。

在windows.h间接导入的WinNT.h中宏定义了“DELETE”为一个整数。

单独编译那个lib工程以及那个使用基本C++的win32 console工程,由于没有导入windows.h,所以编译他们的时候一切正常。但是在MFC工程里面,由于在这个导入是根植于mfc框架中的,无法避免,所以导致了宏定义污染。宏定义在预编译阶段覆盖掉了我的有效标示符,导致莫名其的错误。

相同的问题还出现在STL的max,min一些函数上。


解决:

0,适用#undef xxx来取消xxx的宏定义。

此方法过于暴力,只适用简单情况,对于复杂情况,你undef掉的东西在编译其他库文件的时候是必须的,会导致编译错误。

温和方法:

根本思路是让与编译器认为你的标示符是不同于宏定义中标示符的。

1,最基本的方法就是给自己定义的标示符换个名字,加个前缀。

这样最简单有效,但是不适用于STL组件。

2,名字包装,用括号包裹函数名(定义和调用都要)。

原理是让预编译器看到标示符与“(”之间还有一个“)”,破坏了结构。

特点就是简单。这种方法只适用于带参数的宏定义,即基本只能保护函数,无法保护变量(常量)。但它无法保护成员函数。

因为obj.do()如果写成obj.(do)()是不合语法的。

例如:

#define max(a,b) ((a)>(b)?(a):(b))int (max)() { return 999; } // 用圆括号包装test, 编译器看到 "test)(...)" ,与 "test(...)" 是不一样的符号.
这里这个例子从语义上不太恰当,只用来说明意思。

3,用其他宏间隔开,自己定义一个空的宏。放在函数名与括号之间(和函数名之间要有空格:-))。

这种方法稍微复杂一点。同样只能保护函数,不能保护变量(常量)。但是它可以保护成员函数,和作用域标示符中的函数。

因为在C++中函数名和函数参数列表之间可以有任意多个间隔符。

例如:

#define cal(x) (15+x)#define MYXXXXint cal MYXXX (int x){  return x;}...int x=cal MYXXX  (1);//调用自己的版本int x=cal(1);//调用宏定义的版本


下面是一个完整的例子:

转载要有素质,这个例子来自:http://blog.chinaunix.net/uid-22283027-id-3393561.html

一个完整的测试样例 < vc2005验证通过 >#define test(A,B) ( "call macro test" )#define BOOST_PREVENT_MACRO_SUBSTITUTION// #include <C:\boost_1_45_0\boost/cstdint.hpp>char* (test)(int a, int b){    return "call function test"; }namespace ns{    char* test BOOST_PREVENT_MACRO_SUBSTITUTION(int a,int b)    {    return "call function ns::test"; }}int main ( int, char ** ){    cout <<      test (1,2) << endl; // call macro test    cout <<     (test)(1,2) << endl; // call function test    cout << (ns::test)(1,2) << endl; // call function ns::test    cout <<     test BOOST_PREVENT_MACRO_SUBSTITUTION(1,2) << endl; // call function test    cout << ns::test BOOST_PREVENT_MACRO_SUBSTITUTION(1,2) << endl; // call function ns::test    return 0;}



原载于http://blog.csdn.net/yanxiangtianji

转载请注明出处


原创粉丝点击