Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Еще одной возможностью является применение #ifdef для выбора альтернативных блоков кода, приспособленных к разным реализациям С.
Препроцессор и библиотека С 681
Директива #ifndef
Директива #ifndef может использоваться совместно с директивами #else и #endif тем же самым способом, что и #ifdef. Директива #ifndef выясняет, не определен ли следующий за ней идентификатор; она представляет собой инверсию директивы #ifdef. Эта директива часто применяется для определения константы, если она еще не была определена. Ниже приведен пример.
/* arrays.h */
#ifndef SIZE
#define SIZE 100 #endif
(Более старые реализации С могут не разрешать отступ для директивы #define.) Обычно такая конструкция используется для предотвращения множественных определений одного и того же макроса при включении нескольких заголовочных файлов, каждый из которых может содержать определение. В этом случае определение в первом заголовочном файле становится активным, а последующие определения в других заголовочных файлах игнорируются.
Рассмотрим еще один случай применения. Предположим, что в заголовок файла помещена такая строка:
#include "arrays.h"
В результате константа SIZE будет определена как 100. Однако если поместить в заголовок файла следующий код:
#define SIZE 10 #include "arrays.h"
to SIZE устанавливается в 10. Здесь SIZE определяется до обработки файла arrays.h, поэтому строка #define SIZE 100 пропускается. Такой прием можно использовать, например, при тестировании программы с применением массива меньшего размера. Добившись корректной работы программы, можно удалить оператор #def ine SIZE 10 и провести повторную компиляцию. В этом случае никогда не придется думать о модификации самого заголовочного файла arrays.h.
Директива #ifndef часто используется для предотвращения многократного включения файла. По этой причине заголовочные файлы обычно содержат следующие строки:
/* things.h */
#ifndef THINGS_H_
#define THINGS_H_
/* остальная часть включаемого файла */
#endif
Предположим, что этот файл каким-то образом был включен несколько раз. Когда препроцессор встречает первое включение данного файла, идентификатор THINGS_H_ не определен, поэтому он определяется и обрабатывается остальная часть файла. При появлении следующего включения того же самого файла идентификатор THINGS_H_ уже определен, так что остальная часть файла пропускается.
Из-за чего файл может быть включен несколько раз? Наиболее распространенная причина состоит в том, что многие включаемые файлы содержат директивы включения других файлов, поэтому можно явно включить файл, в котором этот указанный файл уже включен. Почему это является проблемой? Некоторые элементы, помещаемые в заголовочные файлы, такие как объявления типов структур, могут встречать-
682 Глава 16 ся в файле только один раз. Во избежание многократного включения в стандартных заголовочных файлах применяется директива #ifndef. Одна из задач заключается в том, чтобы удостовериться, что проверяемый идентификатор не определен в другом месте. Поставщики библиотек обычно решают ее путем использования имени файла в качестве идентификатора, записывая имя в верхнем регистре, заменяя точки символами подчеркивания и добавляя символ подчеркивания (или, возможно, два) в качестве префикса и суффикса. Если вы заглянете, скажем, в файл stdio.h, то можете обнаружить в нем примерно такой код:
#ifndef _STDIO_H #define _STDIO_H // содержимое файла #endif
Вы можете поступать аналогично. Тем не менее, следует избегать применения символа подчеркивания в качестве префикса, т.к. в стандарте указано, что использование подобного года является зарезервированным. Вряд ли вы захотите случайно определить макрос, который конфликтует с чем-либо в стандартных заголовочных файлах. В листинге 16.10 директива #ifndef используется для защиты от многократного включения заголовочного файла из листинга 16.6.
Листинг 16.10. Заголовочный файл names_st.h
Можете протестировать этот заголовочный файл с помощью программы, приведенной в листинге 16.11. Программа должна работать корректно с заголовочным файлом, показанным в листинге 16.10, и не должна успешно компилироваться, если удалить из листинга 16.10 защиту посредством #ifndef.
Листинг 16.11. Программа doubinc1.c
Препроцессор и библиотека С 683
Директивы #if И #elif
Директива #if во многом похожа на обычный оператор if языка С. За #if следует константное целочисленное выражение, которое считается истинным, когда оно имеет ненулевое значение. В выражении могут применяться логические операции и операции отношения:
#if SYS == 1 #include "ibm.h"
#endif
Для расширения комбинации #if-#else можно использовать директиву #elif (в некоторых старых реализациях она недоступна). Рассмотрим следующий пример:
#if SYS == 1
#include "ibmpc.h"
#elif SYS = 2
#include "vax.h"
#elif SYS == 3
#include "mac.h"
#else
#include "general.h"
#endif
В более новых реализациях предлагается второй способ проверки, определено ли имя. Вместо строки
#ifdef VAX
можно применять следующую форму записи:
#if defined (VAX)
Здесь defined — операция препроцессора, которая возвращает значение 1, если ее аргумент определен с помощью директивы #define, и 0 в противном случае. Преимущество такой новой формы состоит в том, что в нее можно использовать вместе с #elif. Исходя из этого, предыдущий пример можно переписать следующим образом:
#if defined (IBMPC)
#include "ibmpc.h"
#elif defined (VAX)
#include "vax.h"
#elif defined (MAC)
#include "mac.h"
#else
#include "general.h"
#endif
Если приведенные строки применяются, скажем, в системе VAX, идентификатор VAX должен быть определен где-то раньше в этом файле посредством такой строки:
#define VAX
684 Глава 16
Одной из целей использования средств условной компиляции является обеспечение переносимости программы. За счет изменения нескольких ключевых определений в начале файла можно настраивать разные значения и включать определенные файлы для различных систем.
Предопределенные макросы
В стандарте С описано несколько предопределенных макросов, которые перечислены в табл. 16.1.
Таблица 16.1. Предопределенные макросы
Следует отметить, что стандарт С99 предоставляет предопределенный идентификатор func , который расширяется до строкового представления имени содер
жащей его функции. По этой причине данный идентификатор должен иметь область действия в пределах функции, в то время как макросы по существу располагают областью действия на уровне файла. Таким образом, func является предопределен
Читать дальшеИнтервал:
Закладка: