Обходной путь для предупреждения "точка с запятой в глобальной области видимости" для макроса no-op C

В кодовой базе, которая может быть построена как C или C++, я подумал, что сделаю макрос, чтобы использовать преимущества static_assert в случае, если он построен как C++ 11 или выше.

(Примечание: я знаю, что есть способы сделать это до C11 C, по крайней мере, если вы хотите принять параметр сообщения - хотя он не будет работать везде. Но для аргумента позвольте мне сказать, что у меня есть какая-то законная необходимость сделать так, чтобы он не принимал никаких сообщений и был неактивным по крайней мере в некоторых сборках Си.)

Итак, вот простое определение, которое я попробовал:

#if defined(__cplusplus) && __cplusplus >= 201103L
    #define STATIC_ASSERT(cond) \
        static_assert((cond), #cond)
#else
    #define STATIC_ASSERT(cond)
#endif

В макросе нет точки с запятой с намерением добавить ее на место вызова. Но в педантичных настройках предупреждений C этот макрос появляется в глобальной области видимости:

ошибка: ISO C не допускает дополнительного '; вне функции [-Werror = педантичный]

Простое решение, по-видимому, состоит в том, чтобы снять точку с запятой с call-сайтов и поместить ее в сторону C++ 11 макроса. Но я задаюсь вопросом: как сделать макрос "неоперативный" в глобальной области видимости, который позволяет использовать точку с запятой на месте вызова (не сталкиваясь с каким-либо другим предупреждением)?

Ответ 1

Поскольку предварительные объявления структур могут повторяться столько раз, сколько мы хотим, вы можете использовать фиктивное объявление:

#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick

@JonathanLeffler говорит, что это должно работать в старых компиляторах, даже до C11... но:

"Если у вас есть компилятор C90, он будет возражать, если у вас есть статическое утверждение после оператора в составном операторе. Это не ваша основная задача (всегда будет нормально работать с областью файла, если статическое утверждение тоже хорошо), но это не ограничивается использованием в области видимости файла. Однако риск невелик "

Для связанных ситуаций, которые могут не быть полностью недоступными во время компиляции, C11 ввел возможность повторять typedefs. И, как показано в посте, связанном со статическими утверждениями в C до _Static_assert(), есть способы обойти дублирование typedef для старых C, используя номер строки или другой неоднозначный аргумент:

/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b

#if defined(__cplusplus) && __cplusplus >= 201103L
    #define STATIC_ASSERT(cond) \
        static_assert((cond), #cond)
#else
    #define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif

Пока статические утверждения появляются по одному на строку, идентификаторы не будут конфликтовать друг с другом.