Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 [ 35 ] 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

84. Если все альтернативы отпали, то используйте препроцессор

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

#ifdef DEBUG

# define D(x) x #else

# define D(X) /* пусто */

#endif

Вместо макроса D() подставляется его аргумент, если вы занимаетесь отладкой, иначе он расширяется до пустой строки. Он используется так:

D( printf("Это отладочная информация\n"); )

В данном случае аргументом D() является целиком оператор printf() , который исчезает после того, как вы закончите отладку.

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

#ifdef ALLOC

# define I(x) x

# define EXPORTED /* пусто */

#else

# define I(x) /* пусто */

# define EXPORTED extern #endif

EXPORTED int glob x[10] I( ={1, 2, 3, 4} );

EXPORTED some object glob y I( ("конструктор", "аргументы"));

В определенном месте своей программы (я обычно делаю это в файле с именем globals.cpp) вы помещаете следующие строки:

#define ALLOC

#include "globals.h"

Далее везде вы просто включаете этот файл без предварительной директивы #define ALLOC. Когда вы компилируете globals.cpp,



директива #define ALLOC вызывает следующую подстановку:

/* пусто */ int glob x[10] ={1, 2, 3, 4} ;

/* пусто */ some object glob y ("конструктор", "аргументы");

Отсутствие #define ALLOC везде приводит к следующей подстановке:

extern int glob x[10] /* пусто */ ;

extern some object glob y /* пусто */ ;

Последним примером использования препроцессора будет макрос ASSERT() , который выводит сообщение об ошибке и завершает программу, лишь если вы осуществляете отладку (директивой #define определена константа DEBUG) и аргумент ASSERT() имеет значение "ложь". Он очень удобен для тестирования, например, аргументов типа указателей со значением null. Вариант ASSERT(), используемый в виде:

f( char *p)

ASSERT( p, "f() : Неожиданн1Й аргумент NULL." );

определяется следующим образом:

#ifdef DEBUG

#define ASSERT(условие, сообщение) if (!(условие))\

fprintf(stderr, "ASSERT(" #условие ") НЕ ВЫПОЛНЕНО "\

"[Файл " FILE ", Строка %d]:\n\t%s\n",\

LINE , (сообщение) );\

exit( -1 );\

else

#else

# efine ASSERT(c,m) /* пусто */

#endif

В вышеуказанном примере ASSERT() выводит следующую строку при отрицательном результате проверки:

ASSERT(p) НЕ ВЫПОЛНЕНО [Файл whatever.cpp. Строка 123]: f() : Неожиданный аргумент NULL.

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

макросы FILE и LINE . Условие, вызывающее отрицательный

результат, выводится посредством оператора получения строки ANSI Си (символ #), который фактически окружает расширенный аргумент кавычками после выполнения подстановки аргумента. Строка #условие расширяется до "p" в настоящем примере). Затем вступает в действие



обычная конкатенация строк Си для слияния вместе разных строк, создавая единый отформатированный аргумент для fprintf() .

Здесь следует использовать препроцессор, потому что вам нужно вывести на консоль имя файла и номер строки, для которых выполнена проверка. Встроенная функция Си++ может вывести лишь имя того файла с номером строки, в котором определена встроенная функция.

Все компиляторы, поддерживающие стандарт ANSI Си, должны реализовывать макрос assert(expr) в заголовочном файле assert.h, но макрос ANSI Си не может выводить заказанное сообщение об ошибке. Макрос ANSI Си assert() действует, если не определена константа NDEBUG (вариант по умолчанию).



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 [ 35 ] 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76