Какова цель модификаторов h и hh для printf?
помимо %hn
и %hhn
(где h
или hh
задает размер указал на object), в чем смысл h
и hh
модификаторы для
7 ответов
одна из возможных причин: для симметрии с использованием этих модификаторов в форматированный ввод функции? Я знаю, что это не было бы строго необходимо, но, может быть, для этого была ценность?
хотя они не упоминают о важности симметрии для модификаторов" h "и" hh " в обоснование документа C99, комитет упоминает об этом в качестве рассмотрения того, почему спецификатор преобразования "%p " поддерживается для fscanf()
(хотя это было не ново для C99 - поддержка "%p " находится в C90):
преобразование входного указателя с %p было добавлено в C89, хотя это, очевидно, рискованно, для симметрии с fprintf.
В разделе fprintf()
, документ обоснования C99 действительно обсуждает, что" hh " был добавлен, но просто ссылается на читателя :
модификаторы длины %hh и %ll были добавлены в C99 (см. §7.19.6.2).
Я знаю, что это тонкая нить, но я так или иначе, я размышлял, поэтому решил привести любой аргумент.
кроме того, для полноты, модификатор "h" был в исходном стандарте C89 - предположительно, он был бы там, даже если бы это не было строго необходимо из-за широкого существующего использования, даже если бы не было технического требования использовать модификатор.
на %...x
mode, все значения интерпретируются как неподписанные. Поэтому отрицательные числа печатаются как их беззнаковые преобразования. В арифметике дополнения 2, которую использует большинство процессоров, нет разницы в битовых шаблонах между подписанным отрицательным числом и его положительным беззнаковым эквивалентом, который определяется арифметикой модуля (добавление максимального значения для поля плюс один к отрицательному числу, согласно стандарту C99). Много программного обеспечения-особенно отладочный код скорее всего, использовать %x
- делает молчаливое предположение, что битовое представление знакового отрицательного значения и его беззнаковое приведение одинаковы, что верно только на машине дополнения 2.
механика этого приведения такова, что шестнадцатеричные представления значения всегда подразумевают, возможно, неточно, что число было отображено в дополнении 2, если оно не попало в условие ребра, где различные целочисленные представления имеют разные диапазоны. Этот даже справедливо для арифметических представлений, где значение 0 не представлено двоичным шаблоном всех 0s.
отрицательный short
отображается как unsigned long
в шестнадцатеричном поэтому, на любой машине, будет дополнен f
, из-за неявного расширения знака в акции, который printf
будет печатать. The стоимостью то же самое, но это действительно визуально вводит в заблуждение относительно размера поля, подразумевая значительное количество диапазона, которого просто нет подарок.
%hx
усекает отображаемое представление, чтобы избежать этого заполнения, точно так же, как вы пришли к выводу из вашего реального случая использования.
поведение printf
не определено при передаче int
вне диапазона short
это должно быть напечатано как short
, но самая простая реализация на сегодняшний день просто отбрасывает высокий бит raw downcast, поэтому, пока спецификация не требуются любое конкретное поведение, в значительной степени любое вменяемое реализация будет просто выполнять усечение. Впрочем, есть способы и получше.
если printf не заполняет значения или не отображает неподписанные представления подписанных значений,%h
не очень полезно.
единственное, что я могу придумать, это передать unsigned short
или unsigned char
и с помощью %x
спецификатор преобразования. Вы не можете просто использовать голый %x
- значение может быть повышено до int
, а не unsigned int
, а затем у вас есть неопределенное поведение.
ваши альтернативы либо явно привести аргумент к unsigned
; или использовать %hx
/ %hhx
с голым аргументом.
вариативные аргументы для printf()
et al автоматически продвигаются с использованием конверсий по умолчанию, поэтому любой short
или char
значения повышаются до int
при передаче в функцию.
в отсутствие h
или hh
модификаторы, вам нужно будет замаскировать переданные значения, чтобы получить правильное поведение надежно. С модификаторами вам больше не нужно маскировать значения;printf()
реализация делает работу правильно.
в частности, для формата %hx
, код внутри printf()
можно сделать что-то вроде:
va_list args;
va_start(args, format);
...
int i = va_arg(args, int);
unsigned short s = (unsigned short)i;
...print s correctly, as 4 hex digits maximum
...even on a machine with 64-bit `int`!
я беспечно предполагаю, что short
-это 16-битное количество; стандарт на самом деле не гарантирует этого, конечно.
Я счел полезным избегать литья при форматировании неподписанных символов в hex:
sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));
Это незначительное удобство кодирования и выглядит чище, чем несколько слепков (IMO).
Я согласен с вами, что это не обязательно, и поэтому только по этой причине не годится в функции библиотеки C:)
это может быть " хорошо "для симметрии разных флагов, но это в основном контрпродуктивно, потому что он скрывает" преобразование в int
" правила.
еще одно удобное место-проверка размера snprintf. gcc7 добавлена проверка размера при использовании snprintf так что это не удастся
char arr[4];
char x='r';
snprintf(arr,sizeof(arr),"%d",r);
поэтому он заставляет вас использовать больший символ при использовании %d при форматировании char
вот фиксация, которая показывает эти исправления вместо увеличения размера массива символов, который они изменили %d на %h. это также дает более точное описание