如何比较两个同名的预处理宏?

5

我有一个项目,其中有两个不同的预处理器宏具有相同的名称,在两个不同的include文件中定义(来自两个不同的库),我必须在构建时检查它们是否具有相同的值。

到目前为止,我只能在运行时进行此检查,将宏值分配给不同的变量存储在不同的实现文件中,每个文件只包含涉及到的头文件之一。

如何在构建时执行此操作?

这是我迄今为止尝试过的(其中Macro1.h和Macro2.h是我无法修改的第三方文件):

头文件:

TestMultiMacros.h:

#ifndef TEST_MULTI_MACROS_H
#define TEST_MULTI_MACROS_H

struct Values
{
    static const unsigned int val1, val2;
    static const unsigned int c1 = 123, c2 = 123;
};

#endif // TEST_MULTI_MACROS_H

Macro1.h:

#ifndef MACRO1_H
#define MACRO1_H

#define MY_MACRO 123

#endif // MACRO1_H

Macro2.h:

#ifndef MACRO2_H
#define MACRO2_H

#define MY_MACRO 123

#endif // MACRO2_H

实现文件:

TestMultiMacros1.cpp:

#include "TestMultiMacros.h"
#include "Macro1.h"

const unsigned int Values::val1 = MY_MACRO;

TestMultiMacros2.cpp:

#include "TestMultiMacros.h"
#include "Macro2.h"

const unsigned int Values::val2 = MY_MACRO;

entrypoint.cpp:

#include "TestMultiMacros.h"

using namespace std;

static_assert(Values::val1 == Values::val2, "OK");  // error: expression did not evaluate to a constant
static_assert(Values::c1 == Values::c2, "OK");

int main()
{
}

我希望找到一个同时使用C++11和C++17的解决方案。

2个回答

9

在代码中包含第一个头文件。然后将宏的值保存到一个 constexpr 变量中:

constexpr auto foo = MY_MACRO;

然后包含第二个标题。它应该悄悄地覆盖MY_MACRO。如果编译器开始抱怨,请先执行#undef MY_MACRO

然后使用static_assert比较宏的新值和变量:

static_assert(foo == MY_MACRO, "whatever");

3
“它应该悄悄地覆盖MY_MACRO。如果你的编译器开始抱怨,请先使用 #undef MY_MACRO。” 我认为你应该总是先取消第一个宏定义。如果第二个头文件由于某些原因没有定义宏,那么静态断言会无法编译。 - user694733
2
@Pietro 这意味着这些值是不同的。尝试打印 fooMY_MACRO - HolyBlackCat
遗憾的是,如果类型不兼容,那么这种方法就行不通了,但当然它仍然无法编译(从某种意义上说,这也算是任务完成了)。 - stefan
@HolyBlackCat - 除了取消定义宏,没有其他方法了,是吗? - Pietro
2
@Pietro 这个答案似乎适用于Visual C++,因此如果你的断言失败了,那么值就是不同的:https://godbolt.org/z/p7mqQA - VLL
显示剩余3条评论

1
这是一个非常简单的C++17测试,它通过比较宏展开的文本来处理任意(非函数)宏。对于缺乏std::string_viewconstexpr比较的c++11,您可以自己编写几行代码,如this answer所示。
#include <string_view>
#define STRINGIFY(x) STRINGIFY_(x)
#define STRINGIFY_(x) #x

#include "macro1.h"
//#define MY_MACRO A night to remember
constexpr const char* a = STRINGIFY(MY_MACRO);

#undef MY_MACRO
#include "macro2.h"
//#define MY_MACRO A knight to remember
constexpr const char* b = STRINGIFY(MY_MACRO);     

static_assert(std::string_view(a) == b, "Macros differ");

int main() { }

(Godbolt:https://godbolt.org/z/nH5qVo

当然,这取决于您对宏的“相等性”是如何定义的。如果一个头文件有问题,那么这个版本将报告失败。

#define MY_MACRO (2+2)

另一个则拥有

#define MY_MACRO 4

值得注意的是,字符串化会规范化空格,但不会规范化除修剪末尾以外的其他空格。因此,(2 + 2)(2 + 2)将被视为相等,但(2+2)( 2 + 2 )则不会。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接