Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
YAZbIki.doc
Скачиваний:
8
Добавлен:
16.03.2015
Размер:
758.78 Кб
Скачать

Вопрос 17

17. Препроцессор языка C. Основные директивы

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

Имеются следующие директивы препроцессора:

#define #endif #ifdef #line

#elif #error #ifndef #pragma

#else#if#include#undef

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

#include <stdio.h> #include <stdlib.h>

рассматривается как недопустимая.

Директива #define

Директива #define определяет идентификатор и последовательность символов, которая будет подставляться вместо идентификатора каждый раз, когда он встретится в исходном файле. Идентификатор называется именем макроса, а сам процесс замены —макрозаменой[1]. В общем виде директива выглядит таким образом:

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

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

Макроподстановка — это просто замена какого-либо идентификатора связанной с ним последовательностью символов. Поэтому если требуется определить стандартное сообщение об ошибке, то можно написать примерно следующее:

Теперь каждый раз, когда встретится идентификатор E_MS, компилятор будет его заменять строкой "стандартная ошибка при вводе\n". Для компилятора выражение printf() на самом деле будет выглядеть таким образом:

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

вместо сообщения это проверка будет выводиться последовательность символов XYZ.

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

#define LONG_STRING "это очень длинная \

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

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

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

Размер массива balance определяется именем макроса MAX_SIZE, и поэтому если этот размер потребуется в будущем изменить, то надо будет изменить только определение MAX_SIZE. В результате при перекомпиляции программы все обращения к этому имени макроса, находящиеся после измененного определения, будут автоматически изменены.

Определение макросов с формальными параметрами

У директивы #define имеется еще одно большое достоинство: имя макроса может определяться с формальными параметрами. Тогда каждый раз, когда в программе встречается имя макроса, то используемые в его определении формальные параметры заменяются теми аргументами, которые встретились в программе. Такого рода макросы называются макросами с формальными параметрами[2]. Например,

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

.

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

И вот еще что: хотя макросы с формальными параметрами являются полезным средством, но в С99 (и в C++) есть еще более эффективный способ создания машинной программы — с использованием ключевого слово inline.

Директива #error

Директива #error заставляет компилятор прекратить компиляцию. Эта директива используется в основном для отладки. В общем виде директива #error выглядит таким образом:

#еrrоr сообщение-об-ошибке

сообщение-об-ошибкев двойные кавычки не заключается. Когда встречается директива #error, то выводится сообщение об ошибке — возможно, вместе с другой информацией, определяемой компилятором.

Директива #include

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

#include "stdio.h"

#include <stdio.h>

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

Файлы, имена которых находятся в директивах #include, могут в свою очередь содержать другие директивы #include. Они называются вложенными директивами #include. Количество допустимых уровней вложенности у разных компиляторов может быть разным. Однако в стандарте С89 предусмотрено, что компиляторы должны допускать не менее 8 таких уровней. А в стандарте С99 предусмотрена поддержка не менее 15 уровней вложенности.

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

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]