Спецификатор размера
Поле размер позволяет указать размер данных, переданных функции. Необходимость в этом поле объясняется особенностями передачи произвольного количества параметров в функцию в языке Си: функция не может «самостоятельно» определить тип и размер переданных данных, так что информация о типе параметров и точном их размере должна передаваться явно. Рассматривая влияние размерных спецификаций на форматирование целочисленных данных, нужно отметить, что в языке Си имеется цепочка пар знаковых и беззнаковых целых типов, которые в порядке неубывания размеров располагаются так:
Точные размеры типов неизвестны за исключением типов signed char и unsigned char. Парные знаковый и беззнаковый типы имеют одинаковый размер, а значения, представимые в обоих типах, имеют в них одинаковое представление. Тип char имеет одинаковый размер с типами signed char и unsigned char и общий набор представимых значений с одним из этих типов. Далее считается, что char — другое имя одного из этих типов; такое допущение приемлемо для настоящего рассмотрения. Си++ имеет тот же набор типов, за исключением пары long long и unsigned long long. Впрочем, эти типы могут присутствовать в реализациях на правах языковых расширений. Кроме того, в языке Си присутствует тип _Bool, а в Си++ — bool. При передаче в функцию аргументов, которым не соответствуют формальные параметры в прототипе функции (а таковыми являются все аргументы, содержащие выводимые значения), эти аргументы подвергаются стандартным продвижениям, а именно: § аргументы типа float приводятся к типу double; § аргументы типов unsigned char, unsigned short, signed char и short приводятся к одному из следующих типов: § int, если этот тип способен представить все значения исходного типа, или § unsigned в противном случае; § аргументы типов _Bool или bool приводятся к типу int. Таким образом, функции printf не могут получать аргументов типов float, _Bool или bool или целочисленных типов меньших, чем int или unsigned. Набор применяемых спецификаторов размера зависит от спецификатора типа (см. ниже).
Спецификации h и hh используются для компенсации стандартных продвижений типов в сочетании с переходами от знаковых типов к беззнаковым или наоборот. Например, рассмотрим реализацию Си, где тип char знаковый и имеет размер 8 бит, тип int имеет размер 32 бит, используется дополнительный способ кодирования отрицательных целых. char c = 255;printf("%X", c);Такой вызов даст вывод FFFFFFFF, что, возможно, не то, чего ожидал программист. Действительно, значение c равно (char)(-1), а после продвижения типа оно оказывается равно -1. Применение формата %X вызывает интерпретацию данного значения как беззнакового, то есть, 0xFFFFFFFF. char c = 255;printf("%X", (unsigned char)c);char c = 255;printf("%hhX", c);Эти два вызова имеют один и тот же эффект и дают вывод FF. Первый вариант позволяет избежать размножения знака при продвижении типа, второй — компенсирует его уже «внутри» функции printf.
|