В языке С доступны дополнительные форматы для printf(). Первым делом, можно применять префикс h для значений типа short. Следовательно, спецификатор %hd отображает целое число типа short в десятичной форме, а спецификатор %ho отображает это же число в восьмеричной форме. Префиксы h и 1 можно использовать вместе с префиксом и для типов без знака. Например, для вывода значений типов unsigned long можно было бы указать %lu. В листинге 3.4 приведен пример. В системах, поддерживающих типы long long, для версий со знаком и без знака применяются спецификаторы %lld и %llu. Более полное обсуждение спецификаторов формата можно найти в главе 4.
Листинг 3.4. Программа print2 .с

Ниже показан вывод в конкретной системе (результаты могут варьироваться):
un = 3000000000, но не -1294967296
end = 200 и 200
big = 65537, но не 1
verybig = 12345678908642, но не 1942899938
Этот пример демонстрирует, что использование неправильных спецификаторов может привести к неожиданным результатам. Прежде всего, обратите внимание, что применение спецификатора %d для беззнаковой переменной un выдает отрицательное число! Причина в том, что значение 3 000 000 000 без знака и значение -129 496 296 со знаком имеют одно и то же внутреннее представление в памяти нашей системы. (В главе 15 это свойство объясняется более подробно.) Таким образом, если указать функции printf(), что значение является числом без знака, она выведет одно зна-
92 Глава 3 чепие, а если указать, что значение представляет собой число со знаком, то другое значение. Подобное поведение происходит для значений, которые превышают максимально допустимое значение для типа со знаком. Небольшие положительные значения, такие как 96, сохраняются и отображаются одинаково как для типов со знаком, так и для типов без знака.
Далее отметим, что переменная end типа short отображается одинаково независимо от того, указываете вы функции printf() принадлежность end к типу short (спецификатор %hd) или к типу int (спецификатор %d). Это объясняется тем, что при передаче аргумента функции С значение типа short автоматически расширяется до типа int. Здесь могут возникнуть два вопроса: почему предпринимается указанное преобразование, и для чего используется модификатор h? Ответ на первый вопрос прост: для типа int выбирался такой размер, чтобы обеспечить наиболее эффективную его обработку компьютером. Следовательно, на компьютере, в котором типы short и int имеют разные размеры, передача значения как int может осуществляться быстрее. Ответ на второй вопрос выглядит так: модификатор h можно применять, чтобы продемонстрировать, какой вид примет целое значение, будучи усеченным до типа short. Иллюстрацией этого утверждения может служить третья строка вывода. Число 65537, записанное в двоичном формате как 32-битное число, имеет вид 00000000000000010000000000000001. С помощью спецификатора %hd мы заставляем функцию printf() просматривать только последние 16 битов числа, поэтому она отображает в результате 1. Аналогично, финальная строка вывода показывает полное значение verybig, после чего это значение сохраняется в последних 32 битах, на что указывает спецификатор %ld.
Как упоминалось ранее, именно программист отвечает за то, чтобы количество спецификаторов соответствовало количеству отображаемых значений. Теперь вы видите, что программист песет ответственность также и за правильный выбор спецификаторов, соответствующих типу отображаемых значений.
СОВЕТ. Соответствие типов и спецификаторов в printf()
Не забывайте проверять, что для каждого отображаемого значения в операторе printf()
предусмотрен один спецификатор формата. Кроме того, проверяйте, что тип каждого спецификатора формата соответствует типу отображаемого значения.
Использование символов: тип char
Тип данных char применяется для хранения символов, таких как буквы и знаки препинания, однако формально он также является целочисленным. Почему? Причина в том, что тип char в действительности хранит целые числа, а не символы. Для поддержки символов компьютер использует числовой код, в котором определенные целые числа представляют определенные символы. В США наиболее часто применяется код ASCII (приложение В), и он как раз принят в настоящей книге. К примеру, целое значение 65 в нем представляет прописную букву A. Таким образом, чтобы сохранить букву А, фактически нужно записать целое число 65. (Во многих мэйнфреймах IBM используется другой код, EBCDIC, но принцип остается тем же. В компьютерных системах, эксплуатируемых в других странах, могут применяться совершенно другие коды.)
Читать дальше