Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
const char * fmt = "X = %d.\n";
Затем можно использовать fmt в качестве управляющей строки для printf().
В следующей строке 0W заменяется соответствующей строкой. Двойные кавычки делают строку замещения символьной строковой константой. Компилятор сохранит ее в массиве с завершающим нулевым символом. Таким образом, директива
#define HAL 'Z'
определяет символьную константу, а директива
#define НАР "Z"
определяет символьную строку: Z\0.
В этом примере мы применяли обратную косую черту непосредственно перед концом строки, распространяя директиву на следующую строку:
#define 0W "Логика - последнее убежище лишенных\ воображения. - Оскар Уайльд"
Обратите внимание, что вторая строка выровнена влево. Если бы директива имела вид:
#define 0W "Логика - последнее убежище лишенных\ воображения. - Оскар Уайльд"
то вывод был бы таким:
Логика - последнее убежище лишенных воображения. - Оскар Уайльд
Пробелы с начала строки и до слова воображения считаются частью строки. Обычно где бы препроцессор ни обнаружил в программе один из макросов, он заменяет его литерально эквивалентным текстом замены. Если строка замещения содержит вложенные макросы, они также заменяются. Единственным исключением при замене является ситуация, когда найденный макрос заключен в двойные кавычки. Поэтому прока
printf("TWO: OW");
выводит текст: TWO: 0W буквально вместо того, чтобы вывести
2: Логика - последнее убежище лишенных воображения. - Оскар Уайльд Для вывода показанной строки понадобится следующий код: printf("%d: %s\n", TWO, OW);
Здесь имя макроса находится за пределами двойных кавычек.
666 Глава 16
Когда должны использоваться символические константы? Вы должны их применять для большинства числовых констант. Если число представляет собой некоторую константу, участвующую в вычислениях, то символическое имя сделает ее назначение более понятным. Если число является размером массива, то символическое имя упростит его будущее изменение и корректировку границ выполнения циклов. Если число представляет собой системный код, такой как EOF, то символическое имя увеличит степень переносимости программы; понадобится изменять только одно определение EOF. Мнемоническое значения, изменяемость и переносимость — все эти характеристики делают символические константы заслуживающими внимания.
Однако ключевое слово const, которое теперь поддерживается в С, обеспечивает более гибкий способ создания констант. С помощью const можно создавать глобальные и локальные константы, числовые константы, константы в форме массивов и константы в виде структур. С другой стороны, константы-макросы могут использоваться для указания размеров стандартных массивов, а также инициализирующих значений для величин const.
// допустимо
//не обязательно должно быть допустимым // допустимо
//не обязательно должно быть допустимым
Обратите внимание на комментарий “не обязательно должно быть допустимым”. В языке С предполагается, что размер массива для неавтоматических массивов задает ся целочисленным константным выражением, т.е. комбинацией целочисленных констант наподобие 5, констант из перечислений и выражений sizeof. Значения, объявленные с применением const, сюда не входят. (В этом отношении С отличается от C++, где значения const могут быть частью константных выражений.) Тем не менее, реализация компилятора может адаптировать другие формы константных выражений. В результате, к примеру, GCC 4.7.3 не примет объявление для data2, но Clang 4.6 - примет.
Лексемы
Формально тело макроса должно быть строкой лексем, а не строкой символов. Лексемы препроцессора С — это отдельные “слова” в теле определения макроса. Они отделяются друг от друга пробельными символами. Например, определение
#define FOUR 2*2
имеет одну лексему — последовательность 2*2, но определение #define SIX 2 * 3 содержит три лексемы: 2, * и 3.
Строки символов и строки лексем отличаются в том, как трактуются последовательности из множества пробелов. Рассмотрим следующее определение:
#define EIGHT 4*8
Препроцессор, который интерпретирует тело макроса как строку символов, вместо EIGHT подставляет 4 * 8. То есть дополнительные пробелы будут частью за
мены, но препроцессор, который интерпретирует тело как строку лексем, заменит EIGHT тремя лексемами, разделенными одиночными пробелами: 4*8. Другими словами, интерпретация в виде строки символов трактует пробелы как часть тела, а ин-
Препроцессор и библиотека С 667
терпретация в виде строки лексем считает пробелы разделителями между лексемами внутри тела. На практике некоторые компиляторы С рассматривают тела макросов как строки, а не как лексемы. Это различие имеет практическое значение только для более сложных случаев использования по сравнению с приведенными здесь.
Кстати, в компиляторе С принята более сложная трактовка лексем по сравнению с препроцессором. Компилятор понимает правила языка С и не обязательно требует наличия пробелов для отделения лексем друг от друга. Например, компилятор С будет интерпретировать 2*2 как три лексемы, поскольку он выясняет, что 2 является константой, а * — операцией.
Переопределение констант
Предположим, что вы определили константу LIMIT как имеющую значение 20, и затем в том же файле определили ее снова, но уже со значением 25. Такой процесс называется переопределением константы. Политика переопределения зависит от реализации компилятора. Одни реализации считают переопределение ошибкой, если только новое определение не совпадает со старым. Другие разрешают переопределение, возможно, выдавая предупреждение. В стандарте ANSI принят первый вариант, разрешающий переопределение, только если новое определение дублирует предыдущее.
Совпадение определений означает, что их тела должны иметь одни и те же лексемы в том же самом порядке. Поэтому приведенные ниже определения эквивалентны:
#define SIX 2 * 3
#define SIX 2*3
Оба определения содержат те же самые три лексемы, а избыточные пробелы не являются частью тела. Следующее определение рассматривается как отличающееся:
#define SIX 2*3
Оно содержит только одну лексему, а не три, поэтому не совпадает с предыдущими определениями. Если вы хотите переопределить макрос, применяйте директиву #undef, которую мы обсудим позже.
Если требуется переопределить некоторые константы, то для достижения цели может быть проще использовать ключевое слово const и правила области действия.
Использование аргументов в директиве #define
С помощью аргументов можно создавать функциональные макросы, которые выглядят и действуют во многом подобно обычным функциям. Макрос с аргументами очень похож на функцию, потому что аргументы заключаются в круглые скобки. Определения функциональных макросов имеют один или более аргументов в скобках, и эти аргументы затем присутствуют в выражении замены, как показано на рис. 16.2.
Читать дальшеИнтервал:
Закладка: