Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное
в итоге даст 123, поскольку сам xcat не использует оператора ##.
Аналогично сработает и ABSDIFF(ABSDIFF(a, b), c), и мы получим правильный результат.
A12.4. Включение файла
Управляющая строка
#include <имя-файла>
заменяется на содержимое файла с именем имя-файла. Среди символов, составляющих имя-файла, не должно быть знака > и символа новой строки. Результат не определен, если имя-файла содержит любой из символов ", ', или пару символов /*. Порядок поиска указанного файла зависит от реализации.
Подобным же образом выполняется управляющая строка
#include "имя-файла"
Сначала поиск осуществляется по тем же правилам, по каким компилятор ищет первоначальный исходный файл (механизм этого поиска зависит от реализации), а в случае неудачи осуществляется методом поиска, принятым в #include первого типа. Результат остается неопределенным, если имя файла содержит ", или /*; использование знака > разрешается.
Наконец, директива
#include последовательность-лексем
не совпадающая ни с одной из предыдущих форм, рассматривает последовательность лексем как текст, который в результате всех макроподстановок должен дать #include <...> или #include "...". Сгенерированная таким образом директива далее будет интерпретироваться в соответствии с полученной формой.
Файлы, вставляемые с помощью #include, сами могут содержать в себе директивы #include.
A12.5. Условная компиляция
Части программы могут компилироваться условно, если они оформлены в соответствии со следующим схематично изображенным синтаксисом:
условная - конструкция -препроцессора:
if-строка текст elif-части else-частьнеоб #endif
if-строка:
#if константное-выражение
#ifdef идентификатор
#ifndef идентификатор
elif-части:
elif-строка текст
elif-частинеоб
elif-строка:
#elif константное-выражение
else-часть:
else-строка текст
else-строка:
#else
Каждая из директив (if-строка, elif-строка, else-строка и #endif) записывается на отдельной строке. Константные выражения в #if и последующих строках #elif вычисляются по порядку, пока не обнаружится выражение с ненулевым (истинным) значением; текст, следующий за строкой с нулевым значением, выбрасывается. Текст, расположенный за директивой с ненулевым значением, обрабатывается обычным образом. Под словом "текст" здесь имеется в виду любая последовательность строк, включая строки препроцессора, которые не являются частью условной структуры; текст может быть и пустым. Если строка #if или #elif с ненулевым значением выражения найдена и ее текст обработан, то последующие строки #elif и #else вместе со своими текстами выбрасываются. Если все выражения имеют нулевые значения и присутствует строка #else, то следующий за ней текст обрабатывается обычным образом. Тексты "неактивных" ветвей условных конструкций, за исключением тех, которые заведуют вложенностью условных конструкций, игнорируются.
Константные выражения в #if и #elif являются объектами для обычной макроподстановки. Более того, прежде чем просматривать выражения вида
defined идентификатор
и
defined ( идентификатор )
на предмет наличия в них макровызова, они заменяются на 1L или 0L в зависимости от того, был или не был определен препроцессором указанный в них идентификатор. Все идентификаторы, оставшиеся после макрорасширения, заменяются на 0L. Наконец, предполагается, что любая целая константа всегда имеет суффикс L, т. е. вся арифметика имеет дело с операндами только типа long или unsigned long.
Константное выражение (A7.19) здесь используется с ограничениями: оно должно быть целочисленным, не может содержать в себе перечислимых констант, преобразований типа и операторов sizeof.
Управляющие строки
#ifdef идентификатор
#ifndef идентификатор
эквивалентны соответственно строкам
#if defined идентификатор
#if !defined идентификатор
Строки #elif не было в первой версии языка, хотя она и использовалась в некоторых препроцессорах. Оператор препроцессора defined - также новый.
A12.6. Нумерация строк
Для удобства работы с другими препроцессорами, генерирующими Си-программы, можно использовать одну из следующих директив:
#line константа "имя-файла"
#line константа
Эти директивы предписывают компилятору считать, что указанные десятичное целое и идентификатор являются номером следующей строки и именем текущего файла соответственно. Если имя файла отсутствует, то ранее запомненное имя не изменяется. Расширения макровызовов в директиве #line выполняются до интерпретации последней.
A12.7. Генерация сообщения об ошибке
Строка препроцессора вида
#error последовательность-лексемнеоб
приказывает ему выдать диагностическое сообщение, включающее заданную последовательность лексем.
A12.8. Прагма
Управляющая строка вида
#pragma последовательность-лексемнеоб
призывает препроцессор выполнить зависящие от реализации действия. Неопознанная прагма игнорируется.
A12.9. Пустая директива
Строка препроцессора вида
#
не вызывает никаких действий.
A12.10. Заранее определенные имена
Препроцессор "понимает" несколько заранее определенных идентификаторов; их он заменяет специальной информацией. Эти идентификаторы (и оператор препроцессора defined в том числе) нельзя повторно переопределять, к ним нельзя также применять директиву #undef. Это следующие идентификаторы:
__LINE__ Номер текущей строки исходного текста, десятичная константа.
__FILE__ Имя компилируемого файла, строка.
__DATE__ Дата компиляции в виде "MMM DD YYYY",строка.
__TIME__ Время компиляции в виде "hh:mm:ss", строка.
__STDC__ Константа 1. Предполагается, что этот идентификатор определен как 1
только в тех реализациях, которые следуют стандарту.
Строки #error и #pragma впервые введены ANSI-стандартом. Заранее определенные макросы препроцессора также до сих пор не описывались, хотя и использовались в некоторых реализациях.
A13. Грамматика
Ниже приведены грамматические правила, которые мы уже рассматривали в данном приложении. Они имеют то же содержание, но даны в ином порядке.
Здесь не приводятся определения следующих символов-терминов: целая-константа, символьная-константа, константа-с-плавающей-точкой, идентификатор, строка и константа-перечисление. Слова, набранные обычным латинским шрифтом (не курсивом), и знаки рассматриваются как символы-термины и используются точно в том виде, как записаны. Данную грамматику можно механически трансформировать в текст, понятный системе автоматической генерации грамматического распознавателя. Для этого помимо добавления некоторых синтаксических пометок, предназначенных для указания альтернативных продукций, потребуется расшифровка конструкции со словами "один из" и дублирование каждой продукции, использующей символ с индексом необ., причем один вариант продукции должен быть написан с этим символом, а другой - без него. С одним изменением, а именно - удалением продукции typedef-имя:идентификатор и объявлением typedef-имени символом-термином, данная грамматика будет понятна генератору грамматического распознавателя YACC. Ей присуще лишь одно противоречие, вызываемое неоднозначностью конструкции if-else.
единица–трансляции:
внешнее-объявление
единица-трансляции внешнее-объявление
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.


