Вопрос

Помимо %hn и %hhn (где находится h или hh определяет размер направленный на объект), в чем смысл h и hh модификаторы для printf спецификаторы формата?

Из-за повышений по умолчанию, которые стандарт требует применять для функций с переменными значениями, невозможно передать аргументы типа char или short (или любые их подписанные / неподписанные варианты) для printf.

Согласно пункту 7.19.6.1 (7), h модификатор:

Указывает, что следующий спецификатор преобразования d, i, o, u, x или X применяется к аргументу short int или unsigned short int (аргумент будет были повышены в соответствии с целочисленными промо-акциями, но их значение должно быть преобразовано в short int или unsigned short int перед печатью);или что следующий спецификатор преобразования n применяется к указателю на короткий аргумент int.

Если аргумент на самом деле был типа short или unsigned short, затем продвижение по службе до int с последующим преобразованием обратно в short или unsigned short даст то же самое значение в качестве поощрения к int без какого-либо обратного преобразования.Таким образом, для аргументов типа short или unsigned short, %d, %u, и т.д.должны давать идентичные результаты для %hd, %hu, и т.д.(и аналогично для char типы и hh).

Насколько я могу судить, единственная ситуация, когда h или hh модификатор, возможно, может быть полезен, когда аргумент передает ему int вне пределов досягаемости short или unsigned short, например

printf("%hu", 0x10000);

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

Один реальный случай, который я видел, - это код, подобный этому:

char c = 0xf0;
printf("%hhx", c);

там, где автор ожидает его напечатать f0 несмотря на то, что реализация имеет простой char введите подписанный тип (в этом случае, printf("%x", c) напечатал бы fffffff0 или что-то подобное).Но оправдано ли это ожидание?

(Примечание:Что происходит, так это то, что первоначальный тип был char, который получает повышение до int и преобразован обратно в unsigned char вместо того, чтобы char, таким образом изменяя значение, которое выводится на печать.Но определяет ли стандарт такое поведение, или это деталь реализации, на которую может полагаться сломанное программное обеспечение?)

Это было полезно?

Решение

Одна из возможных причин: для симметрии с использованием этих модификаторов в форматированных входных функциях? Я знаю, что это не было бы строго необходимым, но, может быть, для этого была замечена ценность?

Хотя они не упоминают о важности симметрии для модификаторов "H" и "HH" в Обоснование C99 документ, комитет упоминает об этом как соображение того, почему поддерживается спецификатор преобразования «%p» fscanf() (Несмотря на то, что это не было новым для C99 - «%p» поддержки в C90):

Преобразование входного указателя с %P было добавлено в C89, хотя это, очевидно, рискованно, для симметрии с FPRINTF.

В разделе о fprintf(), в документе обоснования C99 обсуждается, что «HH» был добавлен, но просто относится к читателю к fscanf() раздел:

Модификаторы длины %HH и %LL были добавлены в C99 (см. §7.19.6.2).

Я знаю, что это слабая нить, но я все равно размышляю, поэтому я решил, что даю любой аргумент.

Кроме того, для полноты, модификатор «H» был в исходном стандарте C89 - предположительно, он был бы там, даже если бы он не был строго необходимым из -за широкого распространения существующего использования, даже если бы не было технического требования для использования модификатора Анкет

Другие советы

В %...x Режим, все значения интерпретируются как без знака. Таким образом, отрицательные числа напечатаны как их неподписанные конверсии. В арифметике комплемента 2, которую используют большинство процессоров, нет разницы в битовых паттернах между подписанным отрицательным числом и его положительным беззнательным эквивалентом, который определяется арифметикой модуля (добавление максимального значения для поля плюс одно к отрицательному числу, согласно к стандарту C99). Много программного обеспечения- особенно код отладки, скорее всего, будет использовать %x- Приводит к тому, что бесшумное представление о подписанном отрицательном значении и его без знакового актера одинаково, что верно только на машине для комплемента 2.

Механика этого состава такова, что шестигранные представления стоимости всегда подразумевают, возможно, неточно, что число было представлено в комплементе 2, если оно не достигло крайнего условия, где различные целочисленные представления имеют разные диапазоны. Это даже верно для арифметических представлений, где значение 0 не представлено бинарной шаблоном всех 0.

Негатив short отображается как unsigned long Таким образом, в Hexidecimal будет на любой машине f, из -за неявного расширения знаков в продвижении, которое printf будет печатать. А ценность это то же самое, но это действительно визуально вводит в заблуждение в отношении размера поля, подразумевая значительный диапазон, который просто не присутствует.

%hx Усекает отображаемое представление, чтобы избежать этой заполнения, точно так же, как вы заключили из своего реального использования.

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

Если PrintF не значений заполнения или отображает неподписанные представления подписанных значений, %h Не очень полезен.

Единственное использование, которое я могу придумать, - это проход unsigned short или же unsigned char и с использованием %x Спецификатор преобразования. Вы не можете просто использовать голый %x - значение может быть повышено int скорее, чем unsigned int, а затем у вас неопределенное поведение.

Ваши альтернативы либо явно выдвинули аргумент unsigned; или использовать %hx / %hhx с голым аргументом.

Вариационные аргументы в пользу printf() и др. автоматически продвигаются с использованием конверсий по умолчанию, поэтому любые 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-битное количество; Стандарт фактически не гарантирует это, конечно.

Я нашел это полезным, чтобы избежать кастинга при форматировании без подписного Chars в Hex:

        sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));

Это небольшое удобство для кодирования, и выглядит чище, чем несколько слепков (IMO).

еще одно удобное место - проверка размера snprintf.gcc7 добавил проверку размера при использовании snprintf так что это не удастся

char arr[4];
char x='r';
snprintf(arr,sizeof(arr),"%d",r);

таким образом, это вынуждает вас использовать больший символ при использовании %d при форматировании символа

вот коммит, который показывает эти исправления, вместо увеличения размера массива символов они изменили %d на %h.это также даст более точное описание

https://github.com/Mellanox/libvma/commit/b5cb1e34a04b40427d195b14763e462a0a705d23#diff-6258d0a11a435aa372068037fe161d24

Я согласен с вами в том, что это не является строго необходимым, и поэтому по этой причине не очень хороша в функции библиотеки C :)

Это может быть «приятно» для симметрии различных флагов, но в основном это контрпродуктивно, потому что скрывает «обращение в int"Правило.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top