13

In the code below mac_str is char pointer and mac is a uint8_t array:

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

When I try the above code it gives me a warning:

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

but I saw in some code they specified

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

which doesn't give any warning but both are working the same.

What's the need of using hhx instead of just x?

ricardopereira
  • 11,118
  • 5
  • 63
  • 81
Siva Kannan
  • 2,237
  • 4
  • 27
  • 39

3 Answers3

6

hh is a length modifier that specifies the destination type of the argument. The default for conversion format specifier x is unsigned int*. With hh, it becomes unsigned char* or signed char*.

Refer to the table herein for more details.

jrok
  • 54,456
  • 9
  • 109
  • 141
6

&mac[0] is a pointer to an unsigned char.1 %hhx means the corresponding arguments points to an unsigned char. Use square pegs for square holes: the conversion specifiers in the format string must match the argument types.


1 Actually, &mac[0] is a pointer to a uint8_t, and %hhx is still wrong for uint8_t. It “works” in many implementations because uint8_t is the same as unsigned char in many implementations. But the proper format is "%" SCNx8, as in:

#include <inttypes.h>
…
scanf(mac_str, "%" SCNx8 "… rest of format string", &mac[0], … rest of arguments);
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Strictly speaking, I believe that if `uint8_t` exists it must be the same as `unsigned char`. – Stephen Canon Feb 14 '14 at 15:50
  • @StephenCanon: I expect so, but I am having difficulty interpreting C 2011 7.20.1 1: “When typedef names differing only in the absence or presence of the initial **u** are defined,…”. I am wondering whether an implementation could provide `uint8_t` but not provide `int8_t`, due to stubbornness, and then not be compelled by 7.20.1 1 to make `uint8_t` be an `unsigned char` or `char`. Then the implementation could provide another integer type, say `__byte`, that is an unsigned 8-bit integer but is different from `char` or `unsigned char`. So aliasing rules would apply, et cetera. – Eric Postpischil Feb 14 '14 at 17:05
3

hhx converts input to unsigned char, while x converts to unsigned int. And since uint8_t is typedef to unsigned char, hhx fixes warning.

igoris
  • 1,476
  • 10
  • 20