Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
ным идентификатором языка С, а не предопределенным макросом.
В листинге 16.12 демонстрируется ряд предопределенных идентификаторов в действии. Обратите внимание, что некоторые из них являются нововведениями стандарта С99, поэтому компиляторы, разработанные до появления этого стандарта, могут их не принимать. Для компилятора GCC может понадобиться указать флаг -std=c99 или -std=c11.
Листинг 16.12. Программа predef .с
Препроцессор и библиотека С 685
Вот как выглядит вывод, полученный в результате пробного запуска программы:
Директивы #line И terror
Директива #line позволяет переустанавливать нумерацию строк и имя файла, выводимые с помощью макросов LINE_____________________________ и_____ FILE . Директиву #line можно ис
пользовать следующим образом:
#line 1000 //переустанавливает текущий номер строки в 1000
#line 10 "cool.с" //переустанавливает номер строки в 10, а имя файла - в cool. с
Директива #error заставляет препроцессор выдать сообщение об ошибке, которое включает любой текст, указанный в директиве. Если это возможно, процесс компиляции должен приостановиться. Директиву можно применять так:
#if STDC_VERSION != 201112L
#error Несоответствие СИ
#endif
После этого попытка компиляции программы могла бы привести к получению следующих результатов:
$ gcc newish.с
newish.с:14:2 : error: #error Несоответствие СИ $ gcc -std=c11 newish.с
$
Процесс компиляции не проходит, когда компилятор использует более старый стандарт, и завершается успешно, когда применяется стандарт СИ.
Директива #pragma
У современных компиляторов существует несколько настроек, которые можно модифицировать с помощью аргументов командной строки или через меню ШЕ-среды. Директива #pragma позволяет помещать инструкции для компилятора в исходный код. Например, во время разработки стандарта С99 на него ссылались как на С9Х, и в одном из компиляторов использовалась следующая директива для включения поддержки этого стандарта:
#pragma с9х on
В общем случае каждый компилятор имеет собственный набор указаний. Они могут применяться, например, для управления объемом памяти, выделяемой под автоматические переменные, для установки уровня строгости при проверке ошибок или
686 глава 16 для включения нестандартных языковых средств. В стандарте С99 предоставляются три стандартных указания технической природы, которые здесь не рассматриваются.
Кроме того, стандарт С99 поддерживает операцию препроцессора _Pragma. Она преобразует строку в обычное указание компилятору.
Например, операция
_Pragma("nonstandardtreatmenttypeB on") является эквивалентом следующего указания:
#pragma nonstandardtreatmenttypeB on
Поскольку в этой операции не используется символ #, она может выступать в качестве части расширения макроса:
#define PRAGMA(X) _Pragma(#X)
#define LIMRG(X) PRAGMA(STDC CX_LIMITED_RANGE X)
После этого можно применять код вроде показанного ниже:
LIMRG ( ON )
Кстати, следующее определение не работает, хотя выглядит вполне корректным:
#define LIMRG(X) _Pragma(STDC CX_LIMITED_RANGE #X)
Проблема в том, что оно полагается на конкатенацию строк, но компилятор не выполняет конкатенацию до тех пор, пока не завершится работа препроцессора.
Оператор _Pragma выполняет всю работу по превращению из строк, т.е. управляющие последовательности в строке преобразуются в представляющие их символы. Таким образом, вызов операции
_Pragma("use_bool \"true \"false") принимает следующий вид:
#pragma use_bool "true "false
Обобщенный выбор (C11)
Термин обобщенное программирование относится к коду, который не является специфичным для конкретного типа, но после указания типа может транслироваться в код для этого типа. Например, язык C++ позволяет создавать обобщенные алгоритмы в форме шаблонов, которые компилятор затем использует при автоматическом создании экземпляра кода для указанного типа. В языке С нет ничего близко похожего на это. Тем не менее, в СИ появился новый вид выражения, называемого выражением обобщенного выбора, которое можно применять для выбора значения на основе типа выражения, т.е. базируясь на том, является ли типом выражения int, double и т.д. Выражение обобщенного выбора — это не оператор препроцессора, но обычно оно используется как часть определения макроса #define, обладающего определенными чертами обобщенного программирования.
Выражение обобщенного выбора выглядит следующим образом:
_Generic(x, int: 0, float: 1, double: 2, default: 3)
Здесь _Generic — новое ключевое слово С11. Круглые скобки после _Generic содержат несколько элементов, разделенных запятыми. Первый элемент представляет собой выражение, а каждый из оставшихся элементов — тип, за которым следует значение, наподобие float: 1. Тип первого элемента соответствует одной из меток, и значением всего выражения будет значение, указанное после давшей совпадение метки.
Препроцессор и библиотека С 687
Например, предположим, что х в показанном выше выражении является переменной типа int. Тогда тип х соответствует метке int:, приводя к тому, что все выражение получает значение 0. Если тип не соответствует ни одной метке, значением всего выражения становится то, что указано после метки default:. Оператор обобщенного выбора немного похож на оператор switch за исключением того, что сопоставление с метками производится для типа выражения, а не его значения.
Давайте рассмотрим пример объединения оператора обобщенного выбора с определение макроса:
#define MYTYPE(X) _Generic((X),\ int: "int",\ float : "float",\ double: "double",\ default: "other"\
)
Вспомните, что макрос должен быть определен в одной логической строке, но с помощью символа \ одну логическую строку можно разбивать на несколько физических строк. В данном случае выражение обобщенного выбора оценивается как строка. Скажем, вызов макроса MYTYPE (5) оценивается как строка "int", поскольку тип значения 5 соответствует метке int:. В листинге 16.13 приведена дальнейшая иллюстрация этого макроса.
Листинг 16.13. Программа predef .с
Вот вывод программы:
int
double
другой
другой
В последних двух обращениях к MYTYPE() используются типы, не имеющие соответствующих меток, поэтому выбирается строка с меткой default:. Мы могли бы предусмотреть большее число меток, расширив возможности макроса, но этот пример задуман только в качестве демонстрации особенностей работы макросов, основанных
на _Generic.
688 глава 16
При оценке выражения обобщенного выбора программа не вычисляет первый элемент: она только выясняет его тип. Единственным вычисляемым выражением являет ся то, которое указано в совпадающей метке.
Читать дальшеИнтервал:
Закладка: