2013-11-20 4 views
8

Я хотел бы добавить некоторые условные директивы в моем коде, чтобы контролировать другую сборку, например:Существуют ли директивы в препроцессоре C/C++ для преобразования строки в число?

#if VERSION > 100 
/* Compiling here */ 
#endif 

Проблема заключается в том, что «версия» в коде другой, где я не могу изменить. Она была определена как строка:

#define VERSION "101" 

Я интересно, если есть какой-то макрос или директива, которая преобразует строку в номер, так что я могу просто сделать

#if STRING_TO_NUMBER(VERSION) > 100 
/* Compiling here */ 
#endif 

Это возможно, пожалуйста?

PS. Кажется, мое описание не совсем понятно. Основная цель этого требования - контролировать ветвь версии. Например, в старой версии, pre-version 100, эта программа хотела бы old_function(). После этой версии все функции были перенесены в new_function. Поэтому мне нужно написать такие коды:

#if VERSION >= 100 
    old_function(); 
#else 
    new_function(); 
#endif 
#if VERSION >= 100 
int old_function() 
{ 
    ... 
} 
#else 
int new_function() 
{ 
    ... 
} 
#endif 

Вы можете видеть, что будет скомпилирована только одна из функций. Поэтому условие должно быть определено на стадии предварительной обработки, а не во время выполнения.

Сложная часть, VERSION была определена как строка, которая вызвала этот вопрос.

+0

Должен ли быть получен результат на этапе предварительной обработки? Или вы можете использовать функцию 'inline' или' macro'? –

+1

Слишком плохо, что они сделали макрос строкой - легко получить строку из значения макроса (используя оператор '#' 'stringize'), но не так просто, насколько мне известно, не так. –

+0

Вместо этого может быть использован мета-программирование шаблонов. По существу, вызывая или создавая экземпляр другого класса шаблонов на основе версии. вам нужно будет создать тип, основанный на строке VERSION. – Rob

ответ

2

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

Например, GCC 4.8 будет оптимизировать на следующий if тест, оставив только соответствующую руку:

if (strlen(VERSION) > 3 || (strlen(VERSION) == 3 && strcmp(VERSION, "100") > 0)) { 
    // code if VERSION is at least "101" 
} else { 
    // code if VERSION is "100" or less 
} 

Тот факт, что только одна из ветвей if заявление выживает компиляцию легко показать, вставив вызов неопределенной функции в неиспользуемой ветке. С НКУ (и лязгом), и с оптимизацией включен, не производится никакой ошибки линкера:

#include <stdio.h> 
#include <string.h> 
#define VERSION "101" 
// This function is not available for linking 
int unknown_function(); 
// This one is in standard library 
int rand(); 
int main(void) { 
    int x; 
    if (strlen(VERSION) > 3 || (strlen(VERSION) == 3 && strcmp(VERSION, "100") > 0)) { 
     // code if VERSION is at least "101" 
     x = rand(); 
    } else { 
     // code if VERSION is "100" or less 
     x = unknown_function(); 
    } 
    printf("%d\n", x); 
    return 0; 
} 

(Посмотри на http://ideone.com/nGLGTH)


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

constexpr int const_atoi(const char* num, int accum=0) { 
    return *num ? const_atoi(num+1, accum*10 + (*num - '0')) : accum; 
} 

template<bool V_GT_100> struct MoreOrLess_Impl; 
template<> struct MoreOrLess_Impl<false> { 
    // Old prototype 
    void doit(double x) {...} 
}; 
template<> struct MoreOrLess_Impl<true> { 
    // New prototype 
    void doit(long double x) {...} 
}; 
using MoreOrLess = MoreOrLess_Impl<(const_atoi(VERSION) > 100)>; 

// ... 
// ... MoreOrLess::doit(x) ... 

(Глупый пример на http://ideone.com/H1sdNg)

+0

Это не разрешить директивы препроцессора сказать, условно включить один заголовок или другой - иначе '(VERSION [0] - '0') * 100+ (ВЕРСИЯ [1] - '0') * 10 + ВЕРСИЯ [2] - '0'' хватит –

+0

Боюсь, что это не сработает. Функция strlen() - это функция времени выполнения. Но мне нужен исходный код, который обрабатывается на этапе компиляции, поэтому я могу управлять разной библиотекой. – user2023470

+0

@ user2023470: Большинство компиляторов будут оценивать 'strlen (" .... ")' во время компиляции; Я проверил пример, который я предоставил, и никаких следов «if» не осталось для выполнения. Однако это не позволит вам условно #define вещи или условно # включить заголовки. – rici

3

Если вам нужно взаимодействовать с предварительной обработкой для установки других #defines или условно #include различные заголовки. Пока вы не сможете заставить VERSION «фиксироваться» как целое число ...

Единственное, что я могу придумать для вас, это создать крошечный заголовочный файл, определяющий PROPER_VERSION, и включить его, назвав каждый файл номером версии. Так вот вы бы создать:

100: 
#define PROPER_VERSION 100 

101: 
#define PROPER_VERSION 101 

102: 
#define PROPER_VERSION 102 

, а затем вам нужно будет добавить следующее:

#include VERSION 

, а затем использовать PROPER_VERSION, как вам нужно

#if PROPER_VERSION > 100 
... 

Его не шикарно, но я не вижу ничего другого, что вы можете сделать. Вы можете автоматически генерировать файл VERSION.

+0

Спасибо, Гленн. Это не дешевый способ выполнить условную компиляцию. Я использую скрипт для преобразования строки. – user2023470

 Смежные вопросы

  • Нет связанных вопросов^_^