Тест на пустое определение макроса

У меня есть набор отладочных макросов в tracing.hh. Генерирует ли он код и вывод управляется флагом макроса в реальном исходном коде:

// File:  foo.cc
#define TRACING 0
#include "tracing.hh"
// Away we go . . .
TRACEF("debug message");

Флаг TRACING должен иметь значение; Я обычно переключаюсь между 0 и 1.

В файле tracing.h

  • #ifdef TRACING сообщит мне, что трассировка определена.
  • #if TRACING управляет определением функциональных макросов, таких как TRACEF()

Но что, если TRACING не имеет значения? Тогда #if TRACING выдает ошибку:

In file included from foo.c:3:
tracing.hh:73:12: error: #if with no expression

Как я могу проверить, определен ли TRACING, но не имеет значения?


person pdbj    schedule 04.11.2010    source источник


Ответы (3)


С предложением Матти и некоторыми другими замечаниями я думаю, что проблема заключается в следующем: если TRACING не имеет значения, нам нужно допустимое выражение препроцессора в тесте #if .... В руководстве Gnu cpp говорится, что он должен оценивать целочисленное выражение, поэтому нам нужно выражение, которое действительно, даже если один из аргументов отсутствует. В итоге я наткнулся на:

#if (TRACING + 0)
#  . . .
  • Если TRACING имеет числовое значение (как в #define TRACING 2 \n), cpp имеет допустимое выражение, и мы не изменили значение.
  • Если TRACING не имеет значения (как в #define TRACING \n), препроцессор оценивает #if (+0) до false.

Единственный случай, когда это не работает, это

  • Если TRACING имеет нечисловое значение (то есть, ON). В руководстве по cpp говорится: "Идентификаторы, не являющиеся макросами... считаются нулевым числом", что оценивается как false. Однако в этом случае было бы разумнее считать это значением true. Единственные, которые работают правильно, это логические литералы true и false.
person pdbj    schedule 08.11.2010
comment
Вы все еще можете выполнить тест во время выполнения, превратив макрос в строку с помощью оператора #. С++ 11 может превратить это в тест времени компиляции (я полагаю, что использование constexpr может быть способом), но не в препроцессор. - person the swine; 25.11.2015
comment
также у вас нет средств отличить пустое значение от TRACING равного 0 - person Jean-François Fabre; 31.01.2018
comment
В Visual Studio 2017 +0не является допустимым целочисленным выражением. Я изменил его на #if (TRACING - 0), и теперь он работает как часы. - person Alexander Tobias Bockstaller; 26.11.2018

Поздно на вечеринку, но я нашел хороший трюк, чтобы отличить

#define TRACING 0

от

#define DTRACING

как это:

#if (0-TRACING-1)==1 && (TRACING+0)!=-2
#error "tracing empty"
#endif

Если TRACING пусто, выражение оценивается как 0--1 => 1.

Если TRACING равно 0, выражение оценивается как 0-0-1 => -1

Я добавил дополнительную проверку в случае TRACING==-2, которая сделает первый тест пройденным.

Конечно, это не работает для строковых литералов.

person Jean-François Fabre    schedule 31.01.2018
comment
да, я имею в виду это. Спасибо что подметил это. Я не проверял, но думаю, что -DTRACING= тоже можно сделать. - person Jean-François Fabre; 05.06.2019

Бы

#if defined(TRACING) && !TRACING

сделать трюк?

person Matti Virkkunen    schedule 04.11.2010
comment
Почти, я думаю. Смотрите следующий ответ: - person pdbj; 08.11.2010
comment
Это, к сожалению, не сработает. Вы столкнетесь с той же проблемой, когда TRACING будет удален. В итоге вы получите что-то вроде: #ifdefined(TRACING) && ! . Таким образом, ошибка: оператор '!' не имеет правильного операнда, который будет возникать во время сборки. - person ForceMagic; 19.06.2012