如何避免与 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 头文件中定义的宏发生名称冲突?的主要内容,如果未能解决你的问题,请参考以下文章

c语言的宏定义 if defined

如何修复链接源文件时未定义的宏?

如何将系统环境变量作为宏定义放入 C 头文件?

C语言中定义的__FILE__使用,如何只出现该文件名,而不显示路径

如何添加在cmake的宏的定义是啥

如果数组大小发生变化以及定义的宏如何在此处计算偏移量,为啥 C 结构中的字符数组的偏移量会有所不同? [复制]