Заставить компилятор игнорировать некоторые строки в программе

Предположим, что у меня есть 10 000 строк кода на С++. 200 строк этого кода предназначены для тестирования (например, проверьте программу и покажите сообщение об ошибке).

Есть ли способ в С++ игнорировать или рассматривать некоторые строки кода (возможно, с preprocessor)?

Ответ 1

Краткий ответ:

Используйте проверку макросов и #ifdef. Например:

#ifdef MY_CONTROL_MACRO
...
#endif

код внутри этой области будет компилироваться, только если вы уже определили макрос MY_CONTROL_MACRO.


Дополнительные материалы:

  • Чтобы определить такой макрос, вы можете

    • Добавьте #define MY_CONTROL_MACRO в свой код. Или,
    • Для VS добавьте MY_CONTROL_MACRO в Project > Properties > C/C++ > Preprocessor > Preprocessor Definitions. Или,
    • Для GCC скомпилируйте свой код с опцией -DMY_CONTROL_MACRO.
  • Вы можете проверить здесь для получения дополнительной информации.

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

    Управляемый текст внутри условного выражения может включать директивы предварительной обработки. Они выполняются только в том случае, если условие выполнено успешно. Вы можете вложить условные группы внутри других условных групп, но они должны быть полностью вложенными. Другими словами, '#endif всегда совпадает с ближайшим' #ifdef (или '#ifndef, или' #if). Кроме того, вы не можете запускать условную группу в один файл и заканчивать ее другим.

  • Вы также можете использовать расширенный стиль ifdef-else-endif:

    #ifdef MY_CONTROL_MACRO
        ... // this part will be valid if MY_CONTROL_MACRO is defined
    #else
        ... // this part will be valid if MY_CONTROL_MACRO is NOT defined
    #endif
    

Ответ 2

Окружать код с помощью "#ifdef... # endif", а затем использовать параметры компилятора для установки флага:

#ifdef MYTEST_ONLY_FUNCTIONALITY_ENABLED
...
#endif

Затем вы можете использовать параметры компилятора для включения этого кода. Например, в GCC:

-DMYTEST_ONLY_FUNCTIONALITY_ENABLED

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

Ответ 3

Это то, что #ifdef было разработано для

Вы помещаете

#ifdef TESTS
... test code ...
#endif

а затем вы можете перейти к параметрам компилятора, чтобы решить, хотите ли вы скомпилировать тестовую часть или нет. Например, с g++ это

g++ -DTESTS ...

Ответ 4

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

Макрос первоначально существовал для управления выводом assert(3), и он определяется как таковой полностью назад в стандарте POSIX и в меньше, чем C89.

Обратите внимание, что вам нужно отменить тест с помощью #ifndef.

Пример:

#ifndef NDEBUG
    /* Debugging code */
    std::cerr << "So far we have seen " << unicorns << " unicorns" << std::endl;
#endif

P.S. С помощью gcc/g++ вы создаете отладку, добавляя -g в командную строку.

Ответ 5

Использование защиты препроцессора, безусловно, является наиболее гибким и распространенным подходом. Однако, когда это возможно, я предлагаю использовать оператор if. Например, вместо

void example(int a){
   int some_local;
   ...
   #ifdef _DEBUG
   std::cout << "In function " << __FUNCTION__ << "(" << a <<")" << std::endl;
   #endif
   ....
}

Предполагая, что ENABLE_DEBUG определено как 0 или ненулевое, я использовал бы

void example(int a){
   int some_local;

   ...
   if(ENABLE_DEBUG) std::cout << "In function " << __FUNCTION__ << "(" << a <<")" << std::endl;
   ...
}

Поскольку ENABLE_DEBUG является константой, когда ENABLE_DEBUG равно 0, компилятор не будет генерировать код для инструкций, которые он защищает. Итак, зачем использовать этот метод вместо #ifdef?

  • Если во всем коде есть множество отдельных инструкций по отладке, их можно немного легче читать.
  • Что еще более важно, код всегда обрабатывается для синтаксических ошибок, даже если код не генерируется. Это может быть очень полезно, если код отладки не часто включен. Если переменные изменяются (например, в приведенном выше примере, если аргумент a был переименован), то человек, внесший это изменение, будет знать, что он должен также обновить инструкцию debug. Если #ifdefs используются, то он может скрыть бит-гниль, пока кому-то не потребуется включить код отладки, а затем они должны пойти и попытаться исправить код, что может быть неочевидным для них.

Очевидно, что этот подход работает только для операторов отладки внутри тел метода/функции.

Ответ 6

Обогреть свой тестовый код #ifdef DEBUG.

#if DEBUG
   ....
#endif

Ответ 7

Использовать препроцессор #define и #if

в зависимости от вашего компилятора, вы должны иметь некоторые переменные, доступные по умолчанию, например, NDEBUG (для не-отладки) или DEBUG

вы можете определить переменную самостоятельно в коде

#define MY_VARIABLE

и используйте его следующим образом

#ifdef MY_VARIABLE
  //code that compiles only if MY_VARIABLE is defined
  printf("test output here");
#else
  //code that compiles only if MY_VARIABLE is NOT defined
  printf("MY_VARIABLE is not defined");
#endif

для получения дополнительной информации в Интернете для

#define, #if, #ifdef, #ifndef

Ответ 8

Путь к использованию заключается в использовании директивы препроцессора с define, переданной компилятору или взятой из заголовка "config.h":

#if defined(DEBUG) // or #ifdef DEBUG
    // Debug code
#endif

Чтобы избежать использования везде в исходном коде:

#if defined(DEBUG)
    My_Debug_function(some_variable)
#endif

Вы можете сделать в заголовке

#if !defined(DEBUG) // or #ifndef DEBUG
# define My_Debug_function(some_variable) do { static_cast<void>(some_variable); } while (false)  /* Do nothing */
#endif

И поэтому используйте My_Debug_function почти нормально.