5

I have a project where there are two different preprocessor macros with the same name, defined in two different include files (from two different libraries), and I have to check if they have the same value at build time.

So far I could make this check at run time, assigning the macro values to different variables in different implementation files, each including only one of the headers involved.

How can I do it at build time?

This is what I tried so far (where Macro1.h and Macro2.h are third-party files I cannot modify):

Header files:

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

Implementation files:

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()
{
}

I would be interested in a solution using both C++11 and C++17.

2 Answers 2

9

Include the first header. Then save the value of the macro to a constexpr variable:

constexpr auto foo = MY_MACRO;

Then include the second header. It should silently override MY_MACRO. If your compiler starts complaining, do #undef MY_MACRO first.

Then compare the new value of the macro with the variable using a static_assert:

static_assert(foo == MY_MACRO, "whatever");
Sign up to request clarification or add additional context in comments.

8 Comments

"It should silently override MY_MACRO. If your compiler starts complaining, do #undef MY_MACRO first." I say that you should always undef the first macro. If second header doesn't for some reason have the macro defined, static assertion should fail to compile.
I tried with both constexpr and const, and I get this error: "static assertion failed with "whatever""
@Pietro It means the values are different. Try printing foo and MY_MACRO.
Sadly that doesn't work if the types are incompatible, but of course then it still fails to compile (which is mission accomplished, in a sense)
@Pietro This answer seems to work with Visual C++, therefore if the assertion fails for you the values are different: godbolt.org/z/p7mqQA
|
1

Here's a very simple C++17 test which works with arbitrary (non-function) macros by comparing the text of the macro expansion. For c++11, which lacks the constexpr comparison in std::string_view, you can write it yourself in a couple of lines, as shown in 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)

Of course, this depends on what exactly you mean by equality of macros. This version will report failure if one header file has

#define MY_MACRO (2+2)

and the other has

#define MY_MACRO 4

Also worth noting that stringification normalises whitespace but it does not normalise the presence of whitespace other than trimming the ends. So (2 + 2) and (2 + 2) will compare as equal, but not (2+2) and ( 2 + 2 )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.