如何避免与 Windows 头文件中定义的宏发生名称冲突?
Posted
技术标签:
【中文标题】如何避免与 Windows 头文件中定义的宏发生名称冲突?【英文标题】:How do I avoid name collision with macros defined in Windows header files? 【发布时间】:2011-01-20 06:32:24 【问题描述】:我有一些 C++ 代码,其中包含一个名为 CreateDirectory().
的方法,以前该代码仅使用 STL 和 Boost,但最近我必须包含 <windows.h>
,以便查找 CSIDL_LOCAL_APPDATA
。
现在,这段代码:
filesystem.CreateDirectory(p->Pathname()); // Actually create it...
不再编译:
error C2039: 'CreateDirectoryA' : is not a member of ...
对应winbase.h
中的这个宏:
#ifdef UNICODE
#define CreateDirectory CreateDirectoryW
#else
#define CreateDirectory CreateDirectoryA
#endif // !UNICODE
预处理器正在重新定义我的方法调用。有没有办法避免这种命名冲突?还是我必须重命名我的 CreateDirectory()
方法?
【问题讨论】:
现在您知道为什么 Bjarne Stroustrup 想要从 C++ 中去除 C 预处理器——请参阅“C++ 的设计和演变”。 答案可能重复:***.com/questions/1394910/… 请投票:visualstudio.uservoice.com/forums/121579-visual-studio/… 【参考方案1】:如果你只是重命名你的 CreateDirectory 方法,你会更好。如果您需要使用 Windows API,与 Windows.h 竞争是一场失败的战斗。
顺便说一句,如果您在包含 windows.h 时一致,它仍将被编译。 (虽然你可能在其他地方有问题)。
【讨论】:
+1 表示始终包含 windows.h,如果可以的话,+1 表示不与它作斗争并重命名以避免...我在InitiateShutdown()
上遇到了这个问题,所有尝试解决的只是造成了新的问题。
有时很难找到比 MS 取的名字更好的名字。【参考方案2】:
您可以创建一个模块,其唯一目的是 #include <windows.h>
并查找包装在函数中的 CSIDL_LOCAL_APPDATA。
int get_CSIDL_LOCAL_APPDATA(void)
return CSIDL_LOCAL_APPDATA;
顺便说一句,干得好,搞清楚发生了什么!
【讨论】:
【参考方案3】:#undef 创建目录
【讨论】:
【参考方案4】:作为跨平台代码库的开发人员,这是一个问题。处理它的唯一方法是
确保 windows.h - 至少在 Windows 版本上 - 普遍包含在内。然后在您的每个编译单元中定义 CreateDirectory 宏,并普遍用 CreateDirectoryW 代替。预编译的头文件非常适合这个或者,如果那是一个不愉快的提议,(而且对我来说)
将 windows.h 的使用分离到特定于 windows 的实用程序文件中。创建导出基本所需功能的文件。头文件必须使用兼容但不依赖于 windows.h 的数据类型。 cpp 实现文件必须(显然)使用 windows.h。如果您的实用程序函数需要包含带有冲突符号的项目头文件,那么以下模式是必要的:
#include <windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
// etc
#include "some_class_with_CreateDirectory_method.h"
// ...
然后,您需要显式调用您拥有的任何 Windows api 函数的非宏版本#undef'd - CreateDirectoryA 或 W 等。
【讨论】:
【参考方案5】:push
宏,undef
它和pop
宏:
#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
// ...
#pragma pop_macro("CreateDirectory")
【讨论】:
【参考方案6】:您可以备份CreateDirectory
,然后取消定义它,然后在完成您的自定义工作后再次定义它。
#ifdef CreateDirectory
#define CreateDirectory_Backup CreateDirectory
#undef CreateDirectory
#endif
// ...
// Define and use your own CreateDirectory() here.
// ...
#ifdef CreateDirectory_Backup
#define CreateDirectory CreateDirectory_Backup
#undef CreateDirectory_Backup
#endif
【讨论】:
【参考方案7】:请注意,名称冲突通常来自包含的某个头文件。在那之前,像 CreateDirectory 和 GetMessage 这样的东西不会被引入可见性,并且代码编译没有问题。
您可以将这样的包含隔离到一个包装头文件中,并在其末尾添加“#undef whatever”。然后,无论你有什么名字冲突都会消失。当然,除非您需要在自己的代码中使用这些宏(是的,所以非常可能...)
【讨论】:
【参考方案8】:#pragma push_macro("CreateDirectory")
如果没有任何效果,您可以使用自己的命名空间来代替重命名。
【讨论】:
命名空间不能解决这个问题。预处理器正在将他的 CreateDirectory 方法重命名为别的东西。 你是对的,我把问题搞错了。我的解决方案只是重命名的一些糟糕的替代方案。 你应该删除你的答案以上是关于如何避免与 Windows 头文件中定义的宏发生名称冲突?的主要内容,如果未能解决你的问题,请参考以下文章