|
Программирование >> Структурное программирование
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 Обратите внимание, что операция # должна использоваться только в макросе с параметрами, потому что операция # применяется к параметру макроса.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |