Обратный шаг цикла for matlab. Циклы for, while в Матлаб(Matlab). Условные операторы и циклы в MatLab

Заключительная глава книги посвящена описанию препроцессора C++. Препроцессор C++ - это часть компилятора, которая подвергает вашу программу различным текстовым преобразованиям до реальной трансляции исходного кода в объектный. Программист может давать препроцессору команды, называемые директивами препроцессора (preprocessor directives), которые, не являясь формальной частью языка C++, способны расширить область действия его среды программирования.

Препроцессор C++ включает следующие директивы.

Как видите, все директивы препроцессора начинаются с символа "#" .Теперь рассмотрим каждую из них в отдельности.

На заметку. Препроцессор C++ - прямой потомок препроцессора С, и некоторые его средства оказались избыточными после введения в C++ новых элементов. Однако он попрежнему является важной частью С++-среды программирования.

Директива #define

Директива #define определяет имя макроса.

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

#define макроимя последовательность_символов

Обратите внимание на то, что здесь нет точки с запятой. Заданная последовательность_символов завершается только символом конца строки. Между элементамимакроимя (имя_макроса) ипоследовательность_символов может быть любое количество пробелов.

Итак, после включения этой директивы каждое вхождение текстового фрагмента, определенное как макроимя , заменяется заданным элементомпоследовательность_символов . Например, если вы хотите использовать словоUP в качестве значения1 и словоDOWN в качестве значения0 , объявите такие директивы#define .

Данные директивы вынудят компилятор подставлять 1 или0 каждый раз, когда в файле исходного кода встретится словоUP илиDOWN соответственно. Например, при выполнении инструкции:

cout << UP << " " << DOWN << " " << UP + UP;

На экран будет выведено следующее:

После определения имени макроса его можно использовать как часть определения других макроимен. Например, следующий код определяет имена ONE ,TWO иTHREE и соответствующие им значения.

#define TWO ONE+ONE

#define THREE ONE+TWO

Важно понимать, что макроподстановка - это просто замена идентификатора соответствующей строкой. Следовательно, если вам нужно определить стандартное сообщение, используйте код, подобный этому.

Препроцессор заменит строкой "Введите имя файла" каждое вхождение идентификатораGETFILE . Для компилятора эта cout-инструкция

cout << GETFILE;

в действительности выглядит так.

cout << "Введите имя файла";

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

#define GETFILE "Введите имя файла"

cout << "GETFILE - это макроимя\n";

на экране будет отображена эта информация

GETFILE - это макроимя,

Введите имя файла - это макроимя

Если текстовая последовательность не помещается на строке, ее можно продолжить на следующей, поставив обратную косую черту в конце строки, как показано в этом примере.

#define LONG_STRING "Это очень длинная последовательность,\

которая используется в качестве примера."

Среди С++-программистов принято использовать для макроимен прописные буквы. Это соглашение позволяет с первого взгляда понять, что здесь используется макроподстановка. Кроме того, лучше всего поместить все директивы#define в начало файла или включить в отдельный файл, чтобы не искать их потом по всей программе.

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

#define MAX_SIZE 100

float balance;

double index;

int num_emp;

Важно! Важно помнить, что в C++ предусмотрен еще один способ определения констант, который заключается в использовании спецификатора const. Однако многие программисты "пришли" в C++ из С-среды, где для этих целей обычно использовалась директива #define. Поэтому вам еще часто придется с ней сталкиваться в С++-коде.

Макроопределения, действующие как функции

Директива #define имеет еще одно назначение: макроимя может использоваться с аргументами. При каждом вхождении макроимени связанные с ним аргументы заменяются реальными аргументами, указанными в коде программы. Такие макроопределения действуют подобно функциям. Рассмотрим пример.

/* Использование "функциональных" макроопределений. */

#include

using namespace std;

#define MIN(a, b) (((a)<(b)) ? a: b)

cout << "Минимум равен: " << MIN(x, у);

При компиляции этой программы выражение, определенное идентификатором MIN (а, b) , будет заменено, ноx иy будут рассматриваться как операнды. Это значит, что coutинструкция после компиляции будет выглядеть так.

cout << "Минимум равен: " << (((х)<(у)) ? х: у);

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

Макроопределения, действующие как функции, - это макроопределения, которые принимают аргументы.

Кажущиеся избыточными круглые скобки, в которые заключено макроопределение MIN , необходимы, чтобы гарантировать правильное восприятие компилятором заменяемого выражения. На самом деле дополнительные круглые скобки должны применяться практически ко всем макроопределениям, действующим подобно функциям. Нужно всегда очень внимательно относиться к определению таких макросов; в противном случае возможно получение неожиданных результатов. Рассмотрим, например, эту короткую программу, которая использует макрос для определения четности значения.

// Эта программа дает неверный ответ.

#include

using namespace std;

#define EVEN(a) a%2==0 ? 1: 0

if(EVEN(9+1)) cout << "четное число";

else cout << "нечетное число ";

Эта программа не будет работать корректно, поскольку не обеспечена правильная подстановка значений. При компиляции выражение EVEN(9+1) будет заменено следующим образом.

Напомню, что оператор "%" имеет более высокий приоритет, чем оператор"+" . Это значит, что сначала выполнится операция деления по модулю (% ) для числа1 , а затем ее результат будет сложен с числом9 , что (конечно же) не равно0 . Чтобы исправить ошибку, достаточно заключить в круглые скобки аргументa в макроопределенииEVEN , как показано в следующей (исправленной) версии той же программы.

// Эта программа работает корректно.

#include

using namespace std;

#define EVEN(a) (a)%2==0 ? 1: 0

if(EVEN(9+1)) cout << "четное число";

else cout << "нечетное число";

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

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

Важно! Несмотря на то что макроопределения все еще встречаются в C++-коде, макросы, действующие подобно функциям, можно заменить спецификатором inline, который справляется с той же ролью лучше и безопаснее. (Вспомните: спецификатор inline обеспечивает вместо вызова функции расширение ее тела в строке.) Кроме того, inline-функции не требуют дополнительных круглых скобок, без которых не могут обойтись макроопределения. Однако макросы, действующие подобно функциям, все еще остаются частью С++-программ, поскольку многие С/С++-программисты продолжают использовать их по привычке.

Директива #еrror

Директива #error отображает сообщение об ошибке.

Директива #error дает указание компилятору остановить компиляцию. Она используется в основном для отладки. Общий формат ее записи таков.

#error сообщение

Обратите внимание на то, что элемент сообщение не заключен в двойные кавычки. При встрече с директивой#error отображается заданноесообщение и другая информация (она зависит от конкретной реализации рабочей среды), после чего компиляция прекращается. Чтобы узнать, какую информацию отображает в этом случае компилятор, достаточно провести эксперимент.

Директива #include

Директива #include включает заголовок или другой исходный файл.

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

#include

Включает стандартный заголовок для векторов.

При включении другого исходного файла его имя может быть указано в двойных кавычках или угловых скобках. Например, следующие две директивы обязывают C++ прочитать и скомпилировать файл с именем sample.h :

#include

#include "sample.h"

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

Если же имя файла заключено в кавычки, поиск файла выполняется, как правило, в

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

Директивы условной компиляции

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

Директивы #if, #else, #elif и #endif

Директивы #if, #ifdef, #ifndef, #else, #elif и #endif - это директивы условной компиляции.

Главная идея состоит в том, что если выражение, стоящее после директивы #if оказывается истинным, то будет скомпилирован код, расположенный между нею и директивой#endif в противном случае данный код будет опущен. Директива#endif используется для обозначения конца блока#if .

Общая форма записи директивы #if выглядит так.

#if константное_выражение

последовательность инструкций

Если константное_выражение является истинным, код, расположенный непосредственно за этой директивой, будет скомпилирован. Рассмотрим пример.

// Простой пример использования директивы #if.

#include

using namespace std;

cout << "Требуется дополнительная память\n";

При выполнении эта программа отобразит сообщение Требуется дополнительная память на экране, поскольку, как определено в программе, значение константыМАХ больше 10. Этот пример иллюстрирует важный момент: Выражение, которое стоит после директивы#if , вычисляется во время компиляции. Следовательно, оно должно содержать только идентификаторы, которые были предварительно определены, или константы. Использование же переменных здесь исключено.

Поведение директивы #else во многом подобно поведению инструкцииelse , которая является частью языка C++: она определяет альтернативу на случай невыполнения директивы#if . Чтобы показать, как работает директива#else , воспользуемся предыдущим примером, немного его расширив.

// Пример использования директив #if/#else.

#include

using namespace std;

cout << "Требуется дополнительная память.\n");

cout << "Достаточно имеющейся памяти.\n";

В этой программе для имени МАХ определено значение, которое меньше 10, поэтому#if - ветвь кода не скомпилируется, но зато скомпилируется альтернативная #else -ветвь. В результате отобразится сообщениеДостаточно имеющейся памяти. .

Обратите внимание на то, что директива #else используется для индикации одновременно как конца #if -блока, так и начала #еlse -блока. В этом есть логическая необходимость, поскольку только одна директива#endif может быть связана с директивой

#if.

Директива #elif эквивалентна связке инструкций else-if и используется для формирования многозвенной схемы if-else-if , представляющей несколько вариантов компиляции. После директивы#elif должно стоять константное выражение. Если это выражение истинно, следующий блок кода скомпилируется, и никакие другие#elif - выражения не будут тестироваться или компилироваться. В противном случае будет проверено следующее по очереди #elif -выражение. Вот как выглядит общий формат использования директивы#elif .

#if выражение

последовательность инструкций

#elif выражение 1

последовательность инструкций

#elif выражение 2

последовательность инструкций

#еlif выражение 3

последовательность инструкций

#elif выражение N

последовательность инструкций

Например, в этом фрагменте кода используется идентификатор COMPILED_BY , который позволяет определить, кем компилируется программа.

#define COMPILED_BY JOHN

#if COMPILED_BY == JOHN

char who = "John";

#elif COMPILED_BY == BOB

char who = "Bob";

char who = "Tom";

Директивы #if и#elif могут быть вложенными. В этом случае директива#endif ,#else или#elif связывается с ближайшей директивой#if или#elif . Например, следующий фрагмент кода совершенно допустим.

#if COMPILED_BY == BOB

#if DEBUG == FULL

#elif DEBUG == PARTIAL

cout << "Боб должен скомпилировать код" << "для отладки вывода данных.\n";

Директивы #ifdef и #ifndef

Директивы #ifdef и#ifndef предлагают еще два варианта условной компиляции, которые

можно выразить как "если определено"и "если не определено"соответственно.

Общий формат использования директивы #ifdef таков.

#ifdef макроимя

последовательность инструкций

Если макроимя предварительно определено с помощью какой-нибудь директивы#define , то

Общий формат использования директивы #ifndef таков.

#ifndef макроимя

последовательность инструкций

Если макроимя не определено с помощью какой-нибудь директивы#define , топоследовательность инструкций , расположенная между директивами#ifdef и#endif , будет скомпилирована.

Как директива #ifdef , так и директива#ifndef может иметь директиву#else или#elif . Рассмотрим пример.

#include

using namespace std;

cout << "Программист Том.\n";

cout << "Программист неизвестен.\n";

cout << "Имя RALPH не определено.\n";

При выполнении эта программа отображает следующее.

Программист Том.

Имя RALPH не определено.

Но если бы идентификатор ТОМ был не определен, то результат выполнения этой программы выглядел бы так.

Программист неизвестен.

Имя RALPH не определено.

И еще. Директивы #ifdef и#ifndef можно вкладывать точно так же, как и директивы#if .

Директива #undef

Директива #undef используется для удаления предыдущего определения некоторого макроимени. Ее общий формат таков.

#undef макроимя

Рассмотрим пример.

#define TIMEOUT 100

Здесь имена TIMEOUT иWAIT определены до тех пор, пока не выполнится директива

#undef.

Основное назначение директивы #undef - разрешить локализацию макроимен для тех частей кода, в которых они нужны.

Использование оператора defined

Помимо директивы #ifdef существует еще один способ выяснить, определено ли в программе некоторое макроимя. Для этого можно использовать директиву#if в сочетании с оператором времени компиляцииdefined . Например, чтобы узнать, определено ли макроимяMYFILE , можно использовать одну из следующих команд препроцессорной обработки.

#if defined MYFILE

При необходимости, чтобы реверсировать условие проверки, можно предварить оператор defined символом"!" . Например, следующий фрагмент кода скомпилируется только в том случае, если макроимяDEBUG не определено.

#if !defined DEBUG

cout << "Окончательная версия!\n";

О роли препроцессора

Препроцессор C++ - прямой потомок препроцессора языка С, причем без каких-либо усовершенствований. Однако его роль в C++ намного меньше роли, которую играет препроцессор в С. Дело в том, что многие задачи, выполняемые препроцессором в С, реализованы в C++ в виде элементов языка. Страуструп тем самым выразил свое намерение сделать функции препроцессора ненужными, чтобы в конце концов от него можно было бы совсем освободить язык.

На данном этапе препроцессор уже частично избыточен. Например, два наиболее употребительных свойства директивы #define были заменены инструкциями C++. В частности, ее способность создавать константное значение и определять макроопределение, действующее подобно функциям, сейчас совершенно избыточна. В C++ есть более эффективные средства для выполнения этих задач. Для создания константы достаточно определить const -переменную. А с созданием встраиваемой (подставляемой) функции вполне справляется спецификаторinline . Оба эти средства лучше работают, чем соответствующие механизмы директивы#define .

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

"превращения" кода в комментарий делает использование таких директив условной компиляции, как #ifdef , частично избыточным.

Директива #line

Директива #line изменяет содержимое псевдопеременных _ _LINE_ _ и _ _FILE_ _.

Директива #line используется для изменения содержимого псевдопеременных_ _LINE_ _ и_ _FILE_ _ , которые являются зарезервированными идентификаторами (макроименами). Псевдопеременная_ _LINE_ _ содержит номер скомпилированной строки, а псевдопеременная_ _FILE_ _ - имя компилируемого файла. Базовая форма записи этой команды имеет следующий вид.

#line номер "имя_файла"

Здесь номер - это любое положительное целое число, аимя_файла - любой допустимый идентификатор файла. Значение элементаномер становится номером текущей исходной строки, а значение элементаимя_файла - именем исходного файла.Имя_файла

Элемент необязательный. Директива #line используется, главным образом, в целях отладки и в специальных приложениях.

Например, следующая программа обязывает начинать счет строк с числа 200. Инструкция cout отображает номер 202, поскольку это - третья строка в программе после директивной инструкции #line 200 .

#include

using namespace std;

#line 200 // Устанавливаем счетчик строк равным 200.

int main() // Эта строка сейчас имеет номер 200.

{// Номер этой строки равен 201.

cout << _ _LINE_ _;// Здесь выводится номер 202.

Директива #pragma

Директива #pragma зависит от конкретной реализации компилятора.

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

Здесь элемент имя представляет имя желаемой #pragma -инструкции. Если указанное

имя не распознается компилятором, директива #pragma попросту игнорируется без сообщения об ошибке.

Важно! Для получения подробной информации о возможных вариантах использования директивы #pragma стоит обратиться к системной документации по используемому вами компилятору. Вы можете найти для себя очень полезную информацию. Обычно #pragmaинструкции позволяют определить, какие предупреждающие сообщения выдает компилятор, как генерируется код и какие библиотеки компонуются с вашими программами.

Операторы препроцессора "#" и "##"

В C++ предусмотрена поддержка двух операторов препроцессора: "#" и"##" . Эти операторы используются совместно с директивой#define . Оператор"#" преобразует следующий за ним аргумент в строку, заключенную в кавычки. Рассмотрим, например, следующую программу.

#include

using namespace std;

#define mkstr(s) # s

cout << mkstr(Я в восторге от C++);

Препроцессор C++ преобразует строку

cout << mkstr(Я в восторге от C++);

cout << "Я в восторге от C++";

Оператор используется для конкатенации двух лексем. Рассмотрим пример.

#include

using namespace std;

#define concat(a, b) a ## b

cout << concat(x, y);

Препроцессор преобразует строку

cout << concat (x, y);

cout << xy;

Если эти операторы вам кажутся странными, помните, что они не являются операторами "повседневного спроса" и редко используются в программах. Их основное назначение - позволить препроцессору обрабатывать некоторые специальные ситуации.

Зарезервированные макроимена

В языке C++ определено шесть встроенных макроимен.

Рассмотрим каждое из них в отдельности.

Макросы _ _LINE_ _ и_ _FILE_ _ описаны при рассмотрении директивы#line выше в этой главе. Они содержат номер текущей строки и имя файла компилируемой программы.

Макрос _ _DATE_ _ представляет собой строку в форматемесяц/день/год , которая означает дату трансляции исходного файла в объектный код.

Время трансляции исходного файла в объектный код содержится в виде строки в макросе _ _TIME_ _ . Формат этой строки следующий:часы.минуты.секунды .

Точное назначение макроса _ _STDC_ _ зависит от конкретной реализации компилятора. Как правило, если макрос_ _STDC_ _ определен, то компилятор примет только стандартный С/С++-код, который не содержит никаких нестандартных расширений.

Компилятор, соответствующий ANSI/ISO-стандарту C++, определяет макрос_ _cplusplus как значение, содержащее по крайней мере шесть цифр. "Нестандартные" компиляторы должны использовать значение, содержащее пять (или даже меньше) цифр.

Мысли "под занавес"

Мы преодолели немалый путь: длиной в целую книгу. Если вы внимательно изучили все приведенные здесь примеры, то можете смело назвать себя программистом на C++. Подобно многим другим наукам, программирование лучше всего осваивать на практике, поэтому теперь вам нужно писать побольше программ. Полезно также разобраться в С++- программах, написанных другими (причем разными) профессиональными программистами. При этом важно обращать внимание на то, как программа оформлена и реализована. Постарайтесь найти в них как достоинства, так и недостатки. Это расширит диапазон ваших представлений о программировании. Подумайте также над тем, как можно улучшить существующий код, применив контейнеры и алгоритмы библиотеки STL. Эти средства, как правило, позволяют улучшить читабельность и поддержку больших программ. Наконец, просто больше экспериментируйте! Дайте волю своей фантазии и вскоре вы почувствуете себя настоящим С++-программистом!

Для продолжения теоретического освоения C++ предлагаю обратиться к моей книге Полный справочник по C++ , М. : Издательский дом "Вильямс". Она содержит подробное описание элементов языка C++ и библиотек.

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

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

Как видно перед самой компиляцией исходный текст программы обрабатывает препроцессор, давайте познакомимся с его инструкциями поближе.

Начнем с директивы #include, которая заменяется препроцессором на содержимое следующего за ней файла. Пример использования #include:

#include

#include «header2.h»

Если имя файл заключено в угловые скобки, то препроцессор ищет файл в предопределенном месте. Использование двойных скобок предполагает подключение файла с того же каталога, где лежит исходный код компилируемой программы. Стоит также заметить, что подключаемые файлы также могут содержать в себе директивы препроцессора, в частности директиву #include, поэтому могут возникнуть проблемы с многократным подключением одного и того же файла. Для избежания подобного рода путаницы были введены условные директивы, давайте рассмотрим пример их использования:

#ifndef CUCUMBLER_H

#define CUCUMBLER_H

/* содержимое файла cucumbler.h */

Директива #ifndef выполняет проверку не была ли определена константа CUCUMBLER_H ранее, и если ответ отрицательный, то выполняется определение данной константы, и прочего кода, который следует до директивы #endif. Как не сложно догадаться директива #define определяет константу CUCUMBLER_H. В данном случае подобный кусок кода помогает избежать многократного включения одного и того же кода, так как после первого включения проинициализируется константа CUCUMBLER_H и последующие проверки #ifndef CUCUMBLER_H будут возвращать FALSE.

Директива #define широко применяется и при отладке программы.

#include

#include

#include

using namespace std;

cout << "Начало функции main()\n";

vector text_array;

while (cin >> text)

cout << "Прочитан текст: " << text << "\n";

text_array.push_back(text);

Если константа IN_DEBUG не задана, то препроцессор сгенерирует следующий исходник:

#include

#include

#include

using namespace std;

vector text_array;

while (cin >> text)

text_array.push_back(text);

Но если определить IN_DEBUG, то текст программы кардинальным образом поменяется

#include

#include

#include

using namespace std;

cout << "Начало функции main()\n";

vector text_array;

while (cin >> text)

cout << "Прочитан текст: " << text << "\n";

text_array.push_back(text);

Задать препроцессорную константу можно прямо из консоли. Например для компилятора g++ применяется следующий формат

Директивы препроцессора языка си

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

Определение

Назначение

Определение макроса

Отмена определения макроса

Включение объекта-заголовка

Компиляция, если выражение истинно

Компиляция, если макрос определен

Компиляция, если макрос не определен

Компиляция, если выражение в ifложно

Составная директива else/if

Окончание группы компиляции по условию

Замена новым именем строки или имени исходного файла

Формирование ошибок трансляции

Действие определяется реализацией

Null- директива

Директива # define

Директива # define вводит макроопределение или макрос. Общая форма директивы следующая:

# define ИМЯ_МАКРОСА последовательность_символов

Последовательность символов называют еще строкой замещения. Когда препроцессор находит в исходном файле имя_макроса (просто макрос), он заменяет его на последовательность_символов.

Можно отменить определение макроса директивой # undef:

# undef имя_макроса

Данная строка удаляет любую ранее введенную строку замещения. Определение макроса теряется и имя_макроса становится неопределенным.

К примеру, можно определить МАХ как величину 100:

Это значение будет подставляться каждый раз вместо макроса МАХ в исходном файле, Можно также использовать макрос вместо строковой константы:

#defineNAME“TurboC++”

Если последовательность символов в директиве не помещается в одной строке, то можно поставить в конце строки \ и продолжить последовательность на другой строке. Среди программистов принято соглашение, что для имен макросов используются прописные буквы, так как их легко находить в программе. Также все директивы #defineлучше помещать в начало программы.

Директива # define имеет еще одну важную особенность: макрос может иметь аргументы. Каждый раз, когда происходит замена, аргументы заменяются на те, которые встречаются в программе.

Пример : #define MIN(a, b) ((9a)<(b)) ? (a) : (b)

printf(“Минимум из x и y “ % d, MIN(x ,y));

printf(“Минимум из a и b “ % d, MIN(n ,m));

Когда программа будет компилироваться, в выражение, определенное MIN(a,b) будут подставлены соответственноxиyилиmиn. Аргументыaиbзаключены в круглые скобки, так как вместо них может подставляться некоторое выражение, а не просто идентификатор.

Например, printf(“Минимум “ %d,MIN(x*x,x));

Директива # error

Имеет вид: # error сообщение_об_ошибке

Эта команда прекращает компиляцию программы и выдает сообщение об ошибке.

Директивы условной компиляции

К данным директивам относятся: # if , # else , # elif , # endif .

Данные директивы производят выборочную компиляцию программы. Если выражение, следующее за #if, истинно, то коды, заключенные между #ifи #endif, будут компилироваться. В противном случае они при компиляции будут пропущены. Выражение, следующее за #if, проверяется во время компиляции, поэтому оно может содержать только константы и макросы, которые прежде определены. Переменные здесь не могут использоваться.

Директива # else используется так же, как иelseв языке Си.

Пример: Использование условной компиляции.

# include

# define MAX 100

printf(“ MAX равно %d \n”, MAX);

Директива # elif используется для организации вложенной условной компиляции. Форма использования ее следующая:

#if<выражение>

последовательность операторов

#elif<выражение 1>

последовательность операторов

#elif<выражение 2>

последовательность операторов

…………………………………..

Другой метод условной компиляции состоит в использовании директив # ifdef и# ifndef . Основная форма использования этих директив следующая:

# ifdef ИМЯ_МАКРОСА

# endif

и соответственно

# ifndef ИМЯ_МАКРОСА

последовательность операторов

# endif

Если макрос определен, то при использовании # ifdefкомпилируется соответствующая последовательность до операторов #endif. Если же макрос не определен или был отменен директивой #undef, то соответствующая последовательность операторов игнорируется компилятором. Директива #ifndefдействует противоположным образом.




Top