Convert string to GUID with sscanf [closed]
Asked Answered
F

5

7

I'm trying to convert a string to GUID with sscanf:

GUID guid;
sscanf( "11111111-2222-3333-4455-667788995511", "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
        &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]);

However, in runtime, it fails and exits with "Error: Command failed". Why? How to fix it?

I do not want to compile with /clr so cannot use System.

Feebleminded answered 13/5, 2010 at 4:43 Comment(0)
L
5

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++.

Legionary answered 13/5, 2010 at 4:46 Comment(3)
I'm coding in haXe targeting c++, so maybe the error is from the haXe testing program... But the code in the question is in pure c++. When I use UuidFromString("11111111-2222-3333-4455-667788995511",&guid); it says error C2664: 'UuidFromStringA' : cannot convert parameter 1 fr om 'const char *' to 'RPC_CSTR' ...Feebleminded
@Billy: True, but he said he didn't want to use "/clr" which is also Windows-only, so I thought that was an OK assumption to make.Legionary
@Andy: I believe a simple cast would work: const char *str = "..."; UuidFromString((RPC_CSTR) str, &guid);Legionary
G
9

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;
Greatly answered 3/12, 2010 at 0:3 Comment(0)
L
5

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++.

Legionary answered 13/5, 2010 at 4:46 Comment(3)
I'm coding in haXe targeting c++, so maybe the error is from the haXe testing program... But the code in the question is in pure c++. When I use UuidFromString("11111111-2222-3333-4455-667788995511",&guid); it says error C2664: 'UuidFromStringA' : cannot convert parameter 1 fr om 'const char *' to 'RPC_CSTR' ...Feebleminded
@Billy: True, but he said he didn't want to use "/clr" which is also Windows-only, so I thought that was an OK assumption to make.Legionary
@Andy: I believe a simple cast would work: const char *str = "..."; UuidFromString((RPC_CSTR) str, &guid);Legionary
W
4

Working & not damaging the stack:

GUID guid;

sscanf_s(AliasName.c_str(), "{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
        &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]);
Waksman answered 19/2, 2020 at 9:3 Comment(0)
R
2

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.

Resistance answered 15/2, 2018 at 8:10 Comment(0)
K
0

You can also use CLSIDFromString if you want to avoid RPCRT4.DLL dependency - CLSID is simply a GUID, so it will work despite the slightly confusing name.

Kayo answered 15/10, 2013 at 8:21 Comment(1)
'Fraid it will revert looking for a ProgID string in the registry if the UUID is not in the proper format (IIDFromString() will not, though, but requires curlies). Also, there is only a widechar version of it. Unless using COM, I would not go with it (and you'd get a dependency of OLE2.DLL instead of RPCRT4, which is not a fair exchange either). Raymond Chen has more: blogs.msdn.microsoft.com/oldnewthing/20151015-00/?p=91351Resistance

© 2022 - 2024 — McMap. All rights reserved.