简体   繁体   English

如何避免与Windows头文件中定义的宏名称冲突?

[英]How do I avoid name collision with macros defined in Windows header files?

I have some C++ code that includes a method called CreateDirectory(). 我有一些C ++代码,其中包含一个名为CreateDirectory().的方法CreateDirectory(). Previously the code only used STL and Boost, but I recently had to include <windows.h> so I could look-up CSIDL_LOCAL_APPDATA . 以前代码只使用STL和Boost,但我最近不得不包含<windows.h>所以我可以查找CSIDL_LOCAL_APPDATA

Now, this code: 现在,这段代码:

filesystem.CreateDirectory(p->Pathname()); // Actually create it...

No longer compiles: 不再编译:

error C2039: 'CreateDirectoryA' : is not a member of ...

Which corresponds to this macro in winbase.h : 这对应于winbase.h这个宏:

#ifdef UNICODE
#define CreateDirectory  CreateDirectoryW
#else
#define CreateDirectory  CreateDirectoryA
#endif // !UNICODE

The pre-processor is redefining my method call. 预处理器正在重新定义我的方法调用。 Is there any possible way to avoid this naming collision? 有没有办法避免这种命名冲突? Or do I have to rename my CreateDirectory() method? 或者我是否必须重命名我的CreateDirectory()方法?

You will be better off if you just rename your CreateDirectory method. 如果你只是重命名你的CreateDirectory方法,你会更好。 If you need to use windows APIs, fighting with Windows.h is a losing battle. 如果你需要使用Windows API,与Windows.h的战斗是一场失败的战斗。

Incidently, if you were consistent in including windows.h, this will still be compiling. 很明显,如果你在包含windows.h时一致 ,那么仍然会编译。 (although you might have problems in other places). (虽然你可能在其他地方有问题)。

You could create a module whose sole purpose is to #include <windows.h> and look up CSIDL_LOCAL_APPDATA wrapped in a function. 您可以创建一个模块,其唯一目的是#include <windows.h>并查找包含在函数中的CSIDL_LOCAL_APPDATA。

int get_CSIDL_LOCAL_APPDATA(void)
{
    return CSIDL_LOCAL_APPDATA;
}

btw, Well done for working out what happened! 顺便说一句,为搞清楚发生的事情做得好!

#undef CreateDirectory

As a developer working on a cross platform codebase, this is a problem. 作为跨平台代码库的开发人员,这是一个问题。 The only way to deal with it is to 处理它的唯一方法是

  • ensure that windows.h is - on Windows builds at least - universally included. 确保windows.h至少在Windows上构建 - 普遍包含在内。 Then the CreateDirectory macro is defined in every one of your compilation units and is universally substituted with CreateDirectoryW. 然后CreateDirectory宏在每个编译单元中定义,并且通常用CreateDirectoryW替换。 Precompiled headers are ideal for this 预编译头是理想的选择

OR, if that is an unpleasant proposition, (and it is for me) 或者,如果这是一个令人不愉快的主张,(并且它适合我)

  • isolate windows.h usage into windows specific utility files. 将windows.h用法隔离到Windows特定的实用程序文件中。 Create files that export the basic required functionality. 创建导出基本所需功能的文件。 The header files must use data types that are compatible with, but do NOT depend on the inclusion of windows.h. 头文件必须使用与之兼容但不依赖于包含windows.h的数据类型。 The cpp implementation file must (obviously) use windows.h. cpp实现文件必须(显然)使用windows.h。

If your utlility functions need to include project header files with conflicting symbols then the following pattern is a necessity: 如果您的功能需要包含带有冲突符号的项目头文件,那么以下模式是必需的:

#include <windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
// etc
#include "some_class_with_CreateDirectory_method.h"
// ...

You will need to then explicitly call the non macro version of any windows api functions you have #undef'd - CreateDirectoryA or W etc. 然后,您需要显式调用您拥有的任何Windows api函数的非宏版本#undef'd - CreateDirectoryA或W等。

push macro, undef it and pop the macro again: push宏, undef它并再次pop宏:

#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
{
 // ...
}
#pragma pop_macro("CreateDirectory")

Note that name conflict usually comes from a certain header file being included. 请注意,名称冲突通常来自包含的某个头文件。 Until then stuff like CreateDirectory and GetMessage isn't pulled into visibility and code compiles without a problem. 在此之前,像CreateDirectory和GetMessage这样的东西没有被提升到可见性,代码编译没有问题。

You can isolate such an inclusion into a wrapper header file and "#undef whatever" at its end. 您可以将这样的包含隔离到包装头文件中,并在其末尾隔离“#undef whatever”。 Then, whatever name collision you have will be gone. 然后,无论你有什么名字冲突都会消失。 Unless, of course, you need to use those macros in your own code (yeah, so very likely...) 当然,除非您需要在自己的代码中使用这些宏(是的, 非常可能...)

You can take a back up of CreateDirectory , then undefine it, and then define it again when you finish your job with you custom one. 您可以备份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
#pragma push_macro("CreateDirectory")

如果没有任何作用,您可以使用自己的命名空间来代替重命名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM