Программирование >>  Структурное программирование 

1 ... 300 301 302 [ 303 ] 304 305 306 ... 342


17.5. Условная компиляция

Условная компиляция дает возможность программис i-y управ.чять выполнением директив препроцессора и компи.ля1шей программного кода. Каждая условная директива препроцессора вычис.дяет значение целочисленжзго константного выражения. Операции преобразован>1я типов, операция sizeof и константы перечислимого типа не могут участвовать в выражениях, вычисляемых в директивах iijjenpoHeccopa.

Рассмотрим следующее определение макроса с двумя параметрами, вычисляющего площадь прямоугольника:

#define RECTANGLK АРКА(х, у) ( (х) * (у) )

Везде в программе, где встречается идентификатор RECTAN-GLE AREA(x, у), параметры х и у в замещающем тексте макроса будут заменяться значениями соответствующих аргументов и будег выполняться расширение макроса. Например, макрос в операторе

rectArea КЕСТАМПЬК AREA(а + 4, b ь ч);

будет расширен до следующего:

rectArea = { (а 4, * (Ь + 7) ) ;

Значение полученного выражения будет вычисляться и результат будет присваиваться переменной rectArea.

Выражением для подстановки макроса или симвсхтическо!! константы является любой текст в сфоке директивы #define, стдуюпщй за гтдент1к}5и-катором. Если текст для подстановки макроса или символической константы длиннее, чем остаток строки, то в конце сгрокп mojkho иос1авить символ обратного слэша (\), ука:<ывающий на то, что замещающий текст продолжается на следующей стросе.

Определения симвоинческих констант и макросов могут быть аннулированы при помощи директивы препроцессора #undef. Директива #undef отменяет определение снмполической константы или Mincpoca. Область действия символической константы или макроса ттачипается с места их определения и заканчивпется явным, их аннулироваицрм дпре.чтппой #undef или концом файла. Hocjfe аннулирования соотиетству!УП1,ий идепчификатор может быть снова использован в директиве #define.

Функции в стандартной бпблиотетсе иногда опр7.р.;.чкгтсн кате ма?сросы на основе других библиотечных функций. Пачриме(\ и за1олов(>чном файле <stdio.h> обычно опредояется следующий макрос

#defirie qetchai ( ) gctc (stdin)

Макроопределение gelchar испо.дьзует функцию gctc д.чя получени.я символа из стандартного поi .пса ввода. Функция putchar в <stdio.li> и функции обработки симво.тов в ctype.li> часто также вводятся как ма1:рогы. Обратите внимание, что выражечич с побочными .эффектами (па11ри><ер, изменяющие значения переменных) не должны передаваться мл; рпсу i> i ,;i4i. i в(> пртутеп-тов, потому что значентгя аргументов мак]юса могут вычиститься в его теле неоднократно.



Условная директива препроцессора во многом похожа на оператор if. Рассмотрим следующий фрагмент кода:

#if !defined(NULL) #define NULL 0 #endif

Эти директивы определяют, не была ли определена ранее константа NULL. Выражение defined(NULL) дает значение 1, если NULL определена, и О в противном случае. Если результат равен О, то выражение !defined(NULL) дает значение 1 и в следующей строке производится определение константы NULL. В противном случае директива #define пропускается. Каждая директива #if должна заканчиваться своим #endif. Директивы #ifdef и #ifndef являются сокращением выражений #if defined(ииtя) и #if \йеИпей(имя). Можно использовать сложные конструкции условных директив препроцессора при помощи директив #elif (эквивалент else if в структуре if) и #else (эквивалент else в структуре if).

При разработке программы программисты часто находят удобным для себя временно закомментировать большие фрагменты кода и не компилировать их. Если в коде используются комментарии в стиле С, то знаки комментария /* и */ не помогут решить эту задачу. В таком случае программист может использовать следующую конструкцию директив препроцессора

#if О

Фрагмент кода, который не нужно компилировать ttendif

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

Условная компиляция обычно используется как средство отладки. Многие системы программирования на С-Ы- предоставляют разработчику отладчики программ. Однако, сначала нужно изучить этот отладчик и научиться его использовать, что часто вызывает затруднения у студентов и начинающих программистов. Вместо отладчика можно использовать операторы вывода значений переменных, что позволяет контролировать процесс выполнения программы. Эти операторы обкладываются условными директивами препроцессора и компилируются только пока процесс отладки программы не завершен. Например, в следующем фрагменте

ttifdef DEBUG

cerr Переменная х = << х endl; ttendif

оператор вывода в поток сегг будет компилироваться только в случае, если символическая константа DEBUG была определена (директивой #define DEBUG) до директивы #ifdef DEBUG. После завершения процесса отладки директива #define DEBUG может быть просто удалена из исходного файла и операторы вывода, нужные только для целей отладки, будут игнорироваться во время компиляции. В больших программах, возможно, потребуется определять несколько различных символических констант, которые могут управлять условной компиляцией различных частей исходного файла.



Типичная ошибка программирования 17.2

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

17.6. Директивы препроцессора #error и #pragma

Директива препроцессора #error имеет следующий синтаксис

terror лексемы

Директива печатает сообщение об ошибке, зависящее от используемой системы и содержащее заданные в директиве лексемы. Лексемы представляют собой группы символов, отделяемые друг от друга пробелами. Например, директива

terror 1 - Ошибка выхода из диапазона

содержит б лексем. В Borland С-Ь-Ь, например, когда обрабатывается директива #error, лексемы директивы выводятся в качестве сообщения об ошибке, предварительная обработка завершается и программа не компилируется. Директива #pragma

fpragma лексемы

вызывает действия, зависящие от используемой системы. Директива #pragma, не распознанная системой, игнорируется. Borland С-Ь-Ь, например, распознает несколько указаний компилятору - прагм, которые дают возможность программисту полнее использовать возможности системы программирования Borland С-Ь-Ь. За подробной информацией по директивам #error и #pragma обращайтесь к документации по вашей системе программирования на С-Ь-Ь.

17.7. Операции # и ##

Операции препроцессора # и ## доступны в С-Ь-Ь и С ANSI. Операция # преобразует подставляемую лексему в строку символов, взятзоо в кавычки. Рассмотрим следующее макроопределение:

#define HELLO(х) cout Hello, #х endl

Тогда, если в программе встретится макрос HELLO(John), он будет расширяться до

cout Hello, John endl

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

cout Hello, John endl

Обратите внимание, что операция # должна использоваться только в макросе с параметрами, потому что операция # применяется к параметру макроса.



1 ... 300 301 302 [ 303 ] 304 305 306 ... 342

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика