Зачем нужны спецификаторы формата hh и h?

В приведенном ниже коде mac_str — это указатель на символ, а mac — это uint8_t массив:

 sscanf(mac_str,"%x:%x:%x:%x:%x:%x",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]);

Когда я пробую приведенный выше код, он выдает предупреждение:

warning: format ‘%x’ expects argument of type ‘unsigned int *’, but argument 8 has type ‘uint8_t *’ [-Wformat]

но я видел в каком-то коде, который они указали

sscanf(str,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]);

который не дает никаких предупреждений, но оба работают одинаково.

Зачем использовать hhx вместо просто x?


person Siva Kannan    schedule 14.02.2014    source источник
comment
hh означает, как историческое предположение, половина половины. То есть байт.   -  person Joseph Quinsey    schedule 14.02.2014
comment
stackoverflow.com/questions/4586962/   -  person Tim    schedule 14.02.2014
comment
используйте sscanf("%" SCNx8 , &x); ‹inttypes.h›   -  person BLUEPIXY    schedule 14.02.2014
comment
@Джозеф, я не говорил, что это дубликат. Однако в этой другой теме есть некоторая информация, которая может показаться интересной OP.   -  person Tim    schedule 14.02.2014


Ответы (3)


&mac[0] — это указатель на unsigned char.1 %hhx означает, что соответствующие аргументы указывают на unsigned char. Используйте квадратные колышки для квадратных отверстий: спецификаторы преобразования в строке формата должны соответствовать типам аргументов.


1 На самом деле &mac[0] является указателем на uint8_t, а %hhx по-прежнему неверно для uint8_t. Это «работает» во многих реализациях, потому что uint8_t совпадает с unsigned char во многих реализациях. Но правильный формат — "%" SCNx8, например:

#include <inttypes.h>
…
scanf(mac_str, "%" SCNx8 "… rest of format string", &mac[0], … rest of arguments);
person Eric Postpischil    schedule 14.02.2014
comment
Строго говоря, я считаю, что если uint8_t существует, то оно должно быть таким же, как unsigned char. - person Stephen Canon; 14.02.2014
comment
@StephenCanon: Я ожидаю этого, но у меня возникают трудности с интерпретацией C 2011 7.20.1 1: «Когда определены имена typedef, отличающиеся только отсутствием или наличием начального u,…». Мне интересно, может ли реализация предоставить uint8_t, но не предоставить int8_t из-за упрямства, а затем 7.20.1 1 не будет вынуждена сделать uint8_t unsigned char или char. Тогда реализация может предоставить другой целочисленный тип, скажем, __byte, который представляет собой 8-битное целое число без знака, но отличается от char или unsigned char. Таким образом, будут применяться правила псевдонимов и так далее. - person Eric Postpischil; 14.02.2014

hh — это модификатор длины, указывающий конечный тип аргумента. По умолчанию для спецификатора формата преобразования x используется значение unsigned int*. С hh оно становится unsigned char* или signed char*.

Дополнительные сведения см. в таблице herein.

person jrok    schedule 14.02.2014
comment
C11 §7.21.6.2 говорит x .... соответствующий аргумент должен быть указателем на целое число без знака. Я ничего не вижу о signed int*. - person chux - Reinstate Monica; 14.02.2014

hhx преобразует ввод в unsigned char, а x преобразует в unsigned int. А так как uint8_t является typedef для unsigned char, hhx исправляет предупреждение.

person igoris    schedule 14.02.2014