Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015

Тут можно читать онлайн Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - бесплатно полную версию книги (целиком) без сокращений. Жанр: Прочая старинная литература, издательство Вильямс, год 0101. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.

Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - описание и краткое содержание, автор Стивен Прата, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать книгу онлайн бесплатно, автор Стивен Прата
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Макрос Тело замены Рис 162 Части определения функционального макроса 668 - фото 490Макрос Тело замены

Рис. 16,2. Части определения функционального макроса

668 Глава 16

Вот пример определения:

#define SQUARE(X) Х*Х

Оно может применяться в программе следующим образом:

z = SQUARE(2);

Оператор выглядит похожим на вызов функции, хотя поведение макроса не обязательно будет идентичным. В листинге 16.2 иллюстрируется использование этого и второго макроса. В некоторых примерах также обращается внимание на возможные ловушки, поэтому читайте их внимательно.

Листинг 16.2. Программа mac arg.c

Макрос SQUARE имеет следующее определение define SQUAREX ХХ Здесь SQUARE - фото 491

Макрос SQUARE имеет следующее определение:

#define SQUARE(X) Х*Х

Здесь SQUARE — идентификатор макроса, X в SQUARE (X) — аргумент макроса, а Х*Х — список замены. Каждое вхождение SQUARE (х) в листинге 16.2 заменяется х*х. Отличие данного примера от предыдущих состоит в возможности использования в макросе любых символов помимо X. Символ X в определении макроса заменяется символом, который указан при вызове макроса в программе. Таким образом, SQUARE (2) заменяется 2*2, так что X действительно играет роль аргумента.

Однако, как вскоре будет показано, аргумент макроса не работает в точности как аргумент функции. Ниже представлены результаты выполнения программы. Обратите внимание, что некоторые вычисления дают результат, отличающийся от того, что можно было ожидать. На самом деле ваш компилятор может даже выдать не такой результат, как приведенный в предпоследней строке:

Препроцессор и библиотека С 669

х = 5

Вычисление SQUARE(x): Результат: 25.

Вычисление SQUARE(2): Результат: 4.

Вычисление SQUARE(x+2): Результат: 17.

Вычисление 100/SQUARE(2): Результат: 100.

х = 5.

Вычисление SQUARE(++x): Результат: 42.

После инкрементирования х = 7.

Первые две строки вполне предсказуемы, но затем встречается несколько странных результатов. Вспомните, что х имеет значение 5. Это может привести к предположению, что SQUARE (х+2) должно быть 7*7, или 49, но выводится 17 — простое число, но определенно не квадрат! Причина такого вводящего в заблуждение вывода связана с тем, что, как уже говорилось, препроцессор не выполняет вычислений, а просто заменяет последовательности символов. Где бы в определении не появлялось х, препроцессор подставит вместо х символы х+2. Поэтому

х*х

принимает вид:

х+2*х+2

Единственным умножением является 2*х. Если х равно 4, выражение вычисляется следующим образом:

4 + 2*4 + 2 = 4 + 8 + 2 = 14

Этот пример подчеркивает важное отличие между вызовом функции и вызовом макроса. При вызове функции ей передается значение аргумента во время выполнения программы. При вызове макроса лексема аргумента передается в программу перед компиляцией; это другой процесс, происходящий в другое время. Можно ли исправить определение, чтобы вызов SQUARE (х+2) выдавал 36? Конечно. Нужны просто дополнительные круглые скобки:

#define SQUARE(х) (х)*(х)

Теперь SQUARE (х+2) превращается в (х+2) * (х + 2) , и вы получите ожидаемое умножение, поскольку круглые скобки останутся в заменяющей строке.

Однако это не решает всех проблем. Рассмотрим события, которые приводят к тому, что следующая строка:

100/SQUARE(2)

в выводе преобразуется к виду

100/2*2

Согласно приоритетам операций, выражение вычисляется слева направо: (100/2) *2, или 50*2, или 10 0. Для устранения путаницы SQUARE (х) необходимо определить так:

#define SQUARE(х) (х*х)

В результате это дает 100/ (2*2), что в итоге вычисляется как 100/4, или 25.

В следующем определении учтены ошибки обоих примеров:

#define SQUARE(х) ((х)*(х))

Из всего продемонстрированного можно извлечь такой урок: применяйте столько круглых скобок, сколько необходимо для того, чтобы обеспечить корректный порядок выполнения операций.

670 глава 16

Но даже эти меры предосторожности не спасают от ошибки в последнем примере:

SQUARE(++х)

В результате получается:

+ + Х* + +х

Здесь х инкрементируется дважды — один раз до операции умножения и один раз после нее:

++х*++х = 6*7 = 42

Из-за того, что выбор конкретного порядка выполнения операций оставлен за разработчиками реализаций, некоторые компиляторы генерируют умножение 7*6. Есть компиляторы, которые могут инкрементировать оба операнда перед умножением, выдавая в результате 7*7, или 49. На самом деле вычисление этого выражения приводит к ситуации, которая в стандарте называется неопределенным поведением. Тем не менее, во всех этих случаях х начинает со значения 5 и заканчивает значением 7, хотя код выглядит так, будто инкрементирование происходит только один раз.

Простейшее решение этой проблемы — избегать использования ++х как аргумента макроса. Вообще лучше не применять в макросах операции инкремента и декремента. Следует отметить, что выражение++х будет работать в качестве аргумента функции, т.к. оно вычисляется как значение 6, которое затем передается функции.

Создание строк из аргументов макроса: операция #

Рассмотрим следующий функциональный макрос:

#define PSQR(X) printf("Квадрат X равен %d.\n", ((X)*(X)));

Предположим, что этот макрос используется следующим образом:

PSQR(8);

Вот каким будет вывод:

Квадрат X равен 64.

Обратите внимание, что определение X в строке, заключенной в двойные кавычки, трактуется как обычный текст, а не лексема, которую можно заменить.

Представим, что вы хотите поместить аргумент макроса в строку. Язык С позволяет сделать это. Внутри заменяющей части функционального макроса символ # становится операцией препроцессора, которая преобразует лексемы в строки. Пусть х является параметром макроса, тогда #х — это имя параметра, преобразованное в строку "х". Такой процесс называется превращением в строку и демонс трируется в листинге 16.3.

Листинг 16.3. Программа subst.c

Препроцессор и библиотека С 671 Вывод выглядит следующим образом Квадрат у - фото 492

Препроцессор и библиотека С 671

Вывод выглядит следующим образом:

Квадрат у равен 25.

Квадрат 2+4 равен 36.

В первом вызове макроса #х заменяется строкой "у", а во втором вызове вместо #х подставляется "2 + 4". Конкатенация строк ANSI С затем объединяет эти строки с другими строками в операторе printf() для получения финальной строки. Например, первый вызов макроса дает следующий оператор:

printf("Квадрат " "у" " равен %d.\n",((у)*(у)));

После этого конкатенация объединяет три расположенные рядом строки в одну:

"Квадрат у равен %d.\n"

Средство слияния препроцессора: операция ##

Подобно #, операция ## может применяться в заменяющей части функционального макроса. Вдобавок она может использоваться в заменяющей части объектного макроса. Операция ## объединяет две лексемы в одну. Предположим, вы могли бы записать такое определение:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Стивен Прата читать все книги автора по порядку

Стивен Прата - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Язык программирования C. Лекции и упражнения (6-е изд.) 2015 отзывы


Отзывы читателей о книге Язык программирования C. Лекции и упражнения (6-е изд.) 2015, автор: Стивен Прата. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x