Convert string to GUID with sscanf
I think you are damaging the stack. X type specifier requires pointer to int which is at least 4 bytes, so starting from &guid.Data[4] parameter you've screwed up. Provide enough space for sscanf and you should be fine. Final code looks like this:
GUID guid;
unsigned long p0;
int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
int err = sscanf_s(s.c_str(), "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
guid.Data1 = p0;
guid.Data2 = p1;
guid.Data3 = p2;
guid.Data4[0] = p3;
guid.Data4[1] = p4;
guid.Data4[2] = p5;
guid.Data4[3] = p6;
guid.Data4[4] = p7;
guid.Data4[5] = p8;
guid.Data4[6] = p9;
guid.Data4[7] = p10;
Where does "Error: Command failed" come from? It's not a standard error message...
You can use the UuidFromString function to do it in native C++.
Since C++11 and C99 are out there, it is now possible to parse a GUID string right into the GUID structure, using argument size specifiers such as e. g. hh
which stands for a single byte data. However, the correct and portable way that does not depend on the platform sizes of long
, int
and short
is to use macros provided in <inttypes.h>
(or <cinttypes>
for C++11):
#include <inttypes.h>
#define G32 "%8" SCNx32
#define G16 "%4" SCNx16
#define G8 "%2" SCNx8
bool to_guid(const char* str, GUID* guid) {
int nchars = -1;
int nfields =
sscanf(str, "{" G32 "-" G16 "-" G16 "-" G8 G8 "-" G8 G8 G8 G8 G8 G8 "}%n",
&guid->Data1, &guid->Data2, &guid->Data3,
&guid->Data4[0], &guid->Data4[1], &guid->Data4[2], &guid->Data4[3],
&guid->Data4[4], &guid->Data4[5], &guid->Data4[6], &guid->Data4[7],
&nchars);
return nfields == 11 && nchars == 38;
}
#undef G8
#undef G16
#undef G32
The macros in the <inttypes.h>
may be defined differently by different compilers and system bitness; just for the sake of an example, on my system they are defined in <inttypes.h>
as
#define SCNx8 "hhx"
#define SCNx16 "hx"
#define SCNx32 "x"
#define SCNx64 "llx"
The %n
specifier at the end returns the length of the string parsed "so far", so if the string is missing the trailing }
, %n
would not be reached, and nchars
will have the initial value of -1, otherwise it will return the length of the GUID string, which must be 38 (otherwise, e. g. the last byte may parse even if it is a single hex character, which would be invalid for a GUID). The %n
itself is not counted as a "field" for the purposes of sscanf
's return value.
This is still not fantastically correct, as the parser accepts spaces in lieu of leading zeroes for each component, so that the string with strategically placed spaces
{ FACFFB- C-4DF3-A06C-D4 1 A 2 B 3}
will still parse as if it was
{00FACFFB-000C-4DF3-A06C-D4010A020B03}
but this is probably as far as one can get with a single sscanf
.