是否可以在不使用“undef”的情况下重新定义宏?

Is it possible to redefine a macro without the use of ‘undef’?

我正在尝试理解 libspatialindex 源代码。作为 c++ 的新手,我很难理解宏的概念。 库的 API C 包装器,sidx_api.cc,直接和间接包含许多头文件,其中两个似乎定义了相同的宏,涉及连接动态库,没有'undef':

Tools.h

45 #if (defined _WIN32 || defined _WIN64 || defined WIN32 || defined WIN64) && !defined __GNUC__
46  #ifdef SIDX_DLL_EXPORT
47  #define SIDX_DLL __declspec(dllexport)
48  #else
49  #define SIDX_DLL __declspec(dllimport)
50  #endif
51 
52  // Nuke this annoying warning. See http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html
53 #pragma warning( disable: 4251 )
54 
55 #else
56  #define SIDX_DLL
57 #endif

sidx_export.h

29 #pragma once
30 
31 #ifndef SIDX_C_DLL  
32 #if defined(_MSC_VER)
33 # define SIDX_C_DLL __declspec(dllexport)
34 # define SIDX_DLL __declspec(dllexport)
35 #else
36 # if defined(USE_GCC_VISIBILITY_FLAG)
37 # define SIDX_C_DLL __attribute__ ((visibility("default")))
38 # define SIDX_DLL __attribute__ ((visibility("default")))
39 # else
40 # define SIDX_C_DLL
41 # define SIDX_DLL
42 # endif
43 #endif
44 #endif

我认为重新定义一个没有“undef”的宏是有问题的,例如,正如所讨论的here and here。 我在这里错过了什么吗? 谢谢。

如果重新定义它,则需要使用完全相同的预处理标记列表重新定义它。这适用于 function-macros 和 object-macros。

来自6.10.3 Macroreplacement p2

An identifier currently defined as an object-like macro shall not be redefined by another #define preprocessing directive unless the second definition is an object-like macro definition and the two replacement lists are identical.

Likewise, an identifier currently defined as a function-like macro shall not be redefined by another #define preprocessing directive unless the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical.

所以这个定义使用shall.

现在,从4.Conformance p2:

If a ‘‘shall’’or‘‘shall not’’requirement that appears outside of a constraint is violated, the behavior is undefined.

这是官方定义。因此,在重新定义它之前,如果不从预处理器环境中删除宏符号(使用#undef),您会得到未定义的行为。

如果您在某些 C 实现中发现其他情况,这不是标准化的。

正确的做法是根据您在外部设置的某些条件插入不同的定义:

#if COND
#define M M1
#else
#define M M2
#endif

如果你使用一些重新定义它的库,肯定有一些宏设置 COND 并使这些东西得到很好的定义。您需要学习如何使用图书馆。用不同的 pp 令牌列表重新定义它是无效的。

这里没有非法重新定义宏。有些可能会用相同的定义多次定义,这是可以的。构成问题的是 non-identical 个定义。

DLL 本身始终使用由项目设置定义的 SIDX_DLL_EXPORT 构建。使用 DLL 的代码是在未定义此宏的情况下构建的。

第二个header是DLL的一部分。它总是在定义 SIDX_DLL_EXPORT 的情况下编译。因此,它定义的宏(如果有的话)总是与第一个 header 中定义的宏相同。这种相同的重定义不构成问题。