使用 sscanf 将字符串转换为 GUID

发布于 2024-09-01 21:12:40 字数 1468 浏览 0 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

若能看破又如何 2024-09-08 21:12:40

我认为你正在破坏堆栈。 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;

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;
人事已非 2024-09-08 21:12:40

“错误:命令失败”从何而来?这不是标准错误消息...

您可以使用 UuidFromString 函数在本机 C++ 中执行此操作。

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

愁以何悠 2024-09-08 21:12:40

工作与不损坏堆栈:

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

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]);
酒中人 2024-09-08 21:12:40

由于 C++11 和 C99 已经存在,现在可以使用 参数大小说明符,例如代表单字节数据的hh。然而,不依赖于 longintshort 平台大小的正确且可移植的方法是使用 (或 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

中的宏可能因不同的编译器和系统位数而有不同的定义;仅为了举例,在我的系统上,它们在 中定义为

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

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

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

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

仍然会像解析一样进行解析

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

,但这可能是使用单个 < 所能得到的最大结果代码>sscanf。

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.

坠似风落 2024-09-08 21:12:40

如果您想避免 RPCRT4.DLL 依赖性,您也可以使用 CLSIDFromString - CLSID 只是一个 GUID,因此尽管名称有点令人困惑,但它仍然可以工作。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文