- •Вопрос 1
- •Вопрос 2
- •2.4. Константы
- •2.4.1. Целые константы
- •2.4.2. Длинные целые константы
- •2.4.3. Символьные константы
- •2.4.4. Вещественные константы
- •2.4.5. Перечислимые константы
- •2.5. Текстовые константы
- •Вопрос 3
- •2.2. Идентификаторы (имена)
- •2.3. Ключевые слова
- •3.2. Тип
- •Вопрос 4
- •2.3. Данные целого типа
- •Вопрос 5
- •Вопрос 6
- •11.1. Представление символьной строки при помощи одномерного массива
- •11.2. Указатель на символьную строку
- •11.3. Ввод/вывод символьных строк
- •11.4. Массивы символьных строк
- •11.5. Функции работы состроками
- •Вопрос 7
- •3.1. Операции
- •3.1.1. Арифметические операции
- •5.2. Унарные операции
- •5.5. Операции сдвига
- •5.6. Операции отношения
- •5.7. Операции равенства
- •5.8. Побитная операция и
- •5.13. Условная операция
- •3.1.2. Операция присваивания
- •Вопрос 8
- •7.3. Условный оператор if
- •7.7. Оператор выбора switch
- •7.8. Оператор break
- •7.9. Оператор continue
- •7.10. Оператор возврата return
- •6.1.2. Формы оператора if
- •6.1.3. Оператор выбора switch
- •Вопрос 9
- •7.4. Оператор цилка while
- •7.5. Оператор цикла do
- •7.6. Оператор цикла for
- •6.2.1. Оператор while
- •6.2.2. Оператор for
- •6.2.3. Оператор do-while
- •6.3.4. Применение оператора goto и меток
- •Вопрос 11
- •5.2.1. Основные форматы
- •5.2.2. Модификации форматов
- •5.3. Функция форматированного ввода scanf()
- •Вопрос 12
- •12. Работа с файлами в языке c. Функции работы с файлами. Буферизованный ввод-вывод.
- •Вопрос 13
- •1.6.2. Объявления функций
- •1.6.3. Время жизни и область видимости программных объектов
- •1.6.4. Инициализация глобальных и локальных переменных
- •Вопрос 14
- •Вопрос 15
- •Вопрос 16
- •Вопрос 17
- •Вопрос 18
- •Вопрос 19
- •Вопрос 20
Вопрос 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 можно использовать не только для указания имени файла, содержащего обычный исходный текст программы, но и для указания заголовка. В языке С определен набор стандартных заголовков, содержащих необходимую информацию о различных библиотеках этого языка. Заголовок — это стандартный идентификатор, который может соответствовать имени файла, а может и не соответствовать ему. Таким образом, заголовок является просто абстракцией, которая гарантирует наличие некоторой информации. Однако на практике в языке С заголовки почти всегда являются именами файлов.