Как сравнить два макроса препроцессора с одинаковым именем? - PullRequest
5 голосов
/ 13 февраля 2020

У меня есть проект, в котором есть два разных макроса препроцессора с одинаковым именем, определенных в двух разных включаемых файлах (из двух разных библиотек), и я должен проверить, имеют ли они одно и то же значение во время сборки.

До сих пор я мог выполнять эту проверку во время выполнения, назначая значения макросов различным переменным в разных файлах реализации, каждый из которых включает только один из задействованных заголовков.

Как я могу сделать это во время сборки?

Это то, что я пробовал до сих пор (где 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;

точка входа. 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 голосов
/ 13 февраля 2020

Включить первый заголовок. Затем сохраните значение макроса в переменную constexpr:

constexpr auto foo = MY_MACRO;

Затем включите второй заголовок. Следует молча переопределить MY_MACRO. Если ваш компилятор начинает жаловаться, сначала выполните #undef MY_MACRO.

Затем сравните новое значение макроса с переменной, используя static_assert:

static_assert(foo == MY_MACRO, "whatever");
1 голос
/ 13 февраля 2020

Вот очень простой тест C ++ 17, который работает с произвольными (не функциональными) макросами, сравнивая текст расширения макроса. Для c ++ 11, в котором отсутствует сравнение constexpr в std::string_view, вы можете написать его самостоятельно в несколько строк, как показано в в этом ответе .

#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 )

...