Есть ли способ проверить тип значения символа препроцессора в C / C ++ - PullRequest
7 голосов
/ 23 января 2012

Части моего кода зависят от значения символа препроцессора:

int a()
{
#if SDK_VERSION >= 3
    return 1;
#else
    return 2;
#endif
}

Сравнение зависит от значения SDK_VERSION.Ожидается, что это будет целое число или что-то, что сравнивается с целым числом, в данном случае 3. Если SDK_VERSION - это то, что нельзя сравнить с целым числом, произойдет ошибка компиляции.

Есть ли способпрервать компиляцию, если SDK_VERSION не относится к ожидаемому типу?Например:

#if type(SDK_VERSION) != int  # Does not compile, I know
#error "SDK_VERSION must be an integer."
#endif

Ответы [ 6 ]

12 голосов
/ 23 января 2012

Используйте шаблон для генерации такой ошибки:

template<typename T> struct macro_error;

template<> struct macro_error<int> {};

template<typename T> void check(T) 
{ 
   macro_error<T> SDK_VERSION_must_be_int; 
}
int ignored = (check(SDK_VERSION), 0);

Этот код вызовет ошибку компиляции, содержащую следующую строку, если SDK_VERSION не является целым:

SDK_VERSION_must_be_int

Посмотрите демоверсию:

А также обратите внимание на сообщение об ошибке в первом случае. Это печатает это:

prog.cpp:9: error: ‘SDK_VERSION_must_be_int’ has incomplete type
prog.cpp:9: warning: unused variable ‘SDK_VERSION_must_be_int’
4 голосов
/ 23 января 2012

Неа.Причина в том, что символ препроцессора вообще не имеет типа.

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

2 голосов
/ 23 января 2012

Это не скомпилируется, если SDK_VERSION - строка (но она будет работать для float ...):

int get_SDK_Version()
{
    return SDK_VERSION;
}
0 голосов
/ 03 ноября 2012

На самом деле директива #if считает то, что справа, целыми числами.

Так что, если вы хотите достичь того, о чем просили, вы должны сделать некоторую арифметику. Например, сделайте файл test.c с:

#define VERSION 7

#if VERSION
  #if VERSION - (VERSION % 10 )
    #warning Number out of range (1-9)
  #else
    #warning Number in range (1-9)
  #endif
#else
  #warning Zero or not a number
#endif

Компилировать с

gcc -c -o /dev/null test.c

Вы получите сообщение: «Ноль не числа» ... если ваша ВЕРСИЯ равна 0 или не оценивает (с точки зрения препроцессора) как целое число.

И если VERSION оценивается как целое число, вы получите первое или второе сообщение в соответствии с его значением.

Это позволит вам сделать то, что вы искали.

Документация на #if: http://gcc.gnu.org/onlinedocs/cpp/If.html

Обратите внимание, что целое число может быть выражено как: 123 или 0xCC или что-либо, что вычисляется как целочисленная константа после расширения рекурсивного макроса.

Если число с плавающей запятой, например: 3.14, оно считается равным нулю.

Вы не можете просто отличить 0 (целое число) от чего-то, что не является целым числом. Хотя, возможно, существует возможность использования конкатенации макросов, но это еще предстоит изучить.

0 голосов
/ 23 января 2012

Я думаю, вы могли бы использовать здесь несколько шаблонов метапрограммирования.

Я попробую немного магии и опубликую пример, если у меня что-то получится.Моя теория состоит в том, что вы можете создать экземпляр класса или шаблона функции.Определение шаблона по умолчанию приведет к ошибке компиляции, если он не соответствующего типа.Однако специализация шаблона для int не приведет к ошибке.

Это выходит за рамки моего опыта работы с шаблоном и магией препроцессора, но стоит взглянуть на это.Я ожидаю, что проблема в том, что SDK_VERSION - это не что иное, как заменяемый символ.SDK_VERSION сам по себе не имеет типа.

В лучшем случае я думаю, что вы можете проверить, к каким типам он может конвертироваться, но концепция препроцессора, определяемого как «константа», очень ...грубая сила, почти хакерская.Это может быть обычной практикой, но это совсем не безопасно.Лучше всего помнить, что это всего лишь препроцессорная версия поиска и замены.

0 голосов
/ 23 января 2012

Препроцессор не знает типов или каких-либо ключевых слов языка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...