Why does sscanf ignore the specified width?

c++, hex, scanf

Solution

There is a small problem with your code right in the beginning.

const uint8_t* c = "0123456789abcdef0123456789abcdef";

In C++, it is not specified whether a `char` is `signed` or `unsigned`. More precisely, the types `char`, `signed char`, `unsigned char` are distinct, and in fact you have to take this into account when overloading functions and specializing templates.

The code now is:

const char* c = "0123456789abcdef0123456789abcdef";
uint8_t Bytes[16];
for (int i = 0; i < 16; i++) {
    sscanf (&c[2*i], "%2hhx", &(Bytes[i]));
}

Let us analyse your format string:

2  : maximum field witdh to be read
hh : expecting a pointer to signed or unsigned char
x  : means unsigned hex-input

(http://linux.die.net/man/3/scanf)

With this info, it looks correct so far.

From what I can tell, there is no problem in a C99 conforming library *.

*: In this regard, the MSVC library does not support the `hh` specifier.

Problem

I'm using this code to convert a hex string with fixed size 32 to a 16 byte uint8 array. ``` const uint8_t* c = "0123456789abcdef0123456789abcdef"; uint8_t Bytes[16]; for (int i = 0; i < 16; i++) { sscanf (&c[2*i], "%2hhx", &(Bytes[i])); } ``` Despite the `hh` specifying a target width of 1 byte, 4 bytes get written per step. Thus, the code writes 3 bytes past the end of the buffer. Why is that? (For now, I fixed it using a temporary int that gets copied to the array on each step.) To reproduce: ``` #include <stdint.h> #include <string> void main (int argc, char* argv[]) { const char* c = "0123456789abcdef0123456789abcdef"; uint8_t b[20]; for (int i = 0; i < 20; i++) { b[i] = i; } for (int i = 0; i < 16; i++) { sscanf (&c[2*i], "%2hhx", &(b[i])); } for (int i = 0; i < 20; i++) { fprintf(stdout, "%02x\n", (int)(b[i])); } } ``` The expected output is 01 23 45 67 89 ab cd ef 01 23 45 67 89 ab cd ef 10 11 12 13 However, the actual output using Visual Studio 2010 is: 01 23 ... cd ef 00 00 00 13

Original source