代码之家  ›  专栏  ›  技术社区  ›  Andy Li

使用sscanf将字符串转换为guid

  •  4
  • Andy Li  · 技术社区  · 14 年前

    我正在尝试用sscanf将字符串转换为guid:

    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]);
    

    但是,在运行时,它失败并以“错误:命令失败”退出。为什么?如何修复?

    我不想用/clr编译,因此无法使用 System .

    4 回复  |  直到 6 年前
        1
  •  5
  •   Dean Harding    14 年前

    “错误:命令失败”来自何处?这不是标准的错误信息…

    你可以使用 UuidFromString 函数在本地C++中完成。

        2
  •  8
  •   Ivan G.    14 年前

    我认为你在破坏那堆东西。X类型说明符需要指向int的指针,该指针至少为4个字节,因此从&guid.data[4]参数开始,您已经搞砸了。为SScanf提供足够的空间,你应该没事。最终代码如下:

        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;
    
        3
  •  2
  •   kkm -still wary of SE promises    6 年前

    因为C++ 11和C99都在这里,所以现在可以将GUID字符串解析成GUID结构,使用 argument size specifiers 例如 hh 它代表单字节数据。然而,正确和可移植的方式并不取决于平台的尺寸 long , int short 是使用中提供的宏 <inttypes.h> (或) <cinttypes> 对于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
    

    中的宏 <英特尔公司 可能由不同的编译器和系统位定义不同;只是为了一个例子,在我的系统上,它们在 <英特尔公司 作为

    #define SCNx8        "hhx"
    #define SCNx16       "hx"
    #define SCNx32       "x"
    #define SCNx64       "llx"
    

    这个 %n 结尾的说明符返回“到目前为止”分析的字符串的长度,因此,如果字符串缺少尾随 } , %N 无法联系到,并且 nchars 将具有-1的初始值,否则将返回guid字符串的长度,该长度必须为38(否则,例如,即使最后一个字节是一个十六进制字符,也可能会进行解析,这对于guid无效)。这个 %N 出于以下目的,其本身不被视为“字段” sscanf 的返回值。

    这仍然不是非常正确的,因为解析器接受空格而不是每个组件的前导零,因此具有战略性放置空格的字符串

    {  FACFFB-   C-4DF3-A06C-D4 1 A 2 B 3}
    

    仍将像分析一样进行分析

    {00FACFFB-000C-4DF3-A06C-D4010A020B03}
    

    但这可能是一个单人间能做到的 sSCANF .

        4
  •  0
  •   EFraim    11 年前

    如果要避免rpcrt4.dll依赖关系,也可以使用clsidfromstring-clsid只是一个guid,因此尽管名称有点混淆,它仍然可以工作。