c++ 创建一个不是 UUID 类型的全局唯一 id

Posted

技术标签:

【中文标题】c++ 创建一个不是 UUID 类型的全局唯一 id【英文标题】:c++ create a global unique id that is not a UUID type 【发布时间】:2021-12-14 16:58:54 【问题描述】:

在其他语言中,例如 Go,有无数的库可用于创建全局唯一的 ID 字符串(使用元素,例如纳秒时间、机器 ID、进程 ID、随机字节......)

然而,在 C++ 中,唯一真正的选择似乎是 UUID(例如来自 Boost 的)

我希望在我的代码中使用全局唯一标识符,但不希望使用与 UUID 一样多的字符。

作为 GoLang 中可用事物类型的示例。请看下文。 c++中有什么类似的吗?

https://blog.kowalczyk.info/article/JyRZ/generating-good-unique-ids-in-go.html

【问题讨论】:

请注意,当我说“尽可能多的字符”时,我指的是 UUID 的字符串表示 您的“全球唯一性”需要有多严格?传统 UUID 有这么多字符的原因是为了使意外碰撞在统计上不太可能发生,以至于您无需担心它们会在现实生活中发生。较短的 ID 字符串必然包含较少的位,这意味着两个对象共享相同 UUID 的可能性更大。 【参考方案1】:

请注意,当我说“尽可能多的字符”时,我指的是 UUID 的字符串表示

所以,也许使用你自己的表示。

你没有指定很多。请记住,时间聚类可能会导致安全漏洞¹。我假设 UUIDv4 标准,即 16 个字节。让我们使用链接页面中看起来很短的编码:

Live On Coliru

#include <boost/lexical_cast.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <cstring>
#include <iostream>
#include <string_view>

using boost::uuids::uuid;
static_assert(uuid::static_size() == 16);

static constexpr auto alphabet57 =
    "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

std::string encode57(uuid uid) 
    boost::uint128_type num;
    std::reverse(uid.data, uid.data+16);
    std::memcpy(&num, uid.data, 16);

    std::string s;
    s.reserve(12);

    while (num) 
        s += alphabet57[num % 57];
        num /= 57;
    

    return s;


uuid decode57(std::string_view s) 
    boost::uint128_type num = 0;

    for (auto it = s.rbegin(); it != s.rend(); ++it) 
        num *= 57;
        num += std::find(alphabet57, alphabet57 + 57, *it) - alphabet57;
    

    uuid uid;
    std::memcpy(uid.data, &num, 16);
    std::reverse(uid.data, uid.data + 16);

    return uid;


int main() 
    for (std::string test : 
             "f7dd5274-f457-4239-a881-801662d589ad", // sfitJnfge8vaXnga8kzi7n
             "3b387615-24ed-4c17-a715-c4413ffac3b5", // Vq6uZe6usvSwWftVdBPbYC
             "3dd64dba-1ff3-40e5-84e3-3fbb0f8b86b9", // r5D3drtfrx7322ajzYv82D
             "b17a848e-5d6b-45d9-ae25-57cfb8a8fec3", // petYHah9W3p8GptQ9QJuaZ
             "a9edc682-147c-4e41-85e2-e06c4ce64086", // DFLa6tquGSZvSEi2WE3MFY
             "2cc90c4a-192f-4b57-bc11-2c322dab2ce0", // yyg6AekktrpjdBCjGjsCy9
             "ac1d94bd-3fbc-46c1-aeec-cdcdc2dd0dd2", // dzHCNTADG6R4n3QTjm7XdY
             "1e3df271-a3c2-4b45-8871-0fde4c2d97e8", // tL66L6gqRESaABWsxbrhP7
             "0d15c1d5-3646-474f-8a5d-989878f12a95", // FtnvH2QRENpsFcLXq5zhL4
             "ececc5dc-cdf1-49f4-b3f7-bfe8697133fd", // Dkfm7JmgVAuP28JLPDBnAk
         )                                          //
    
        auto const uid = boost::lexical_cast<uuid>(test);
        auto const txt = encode57(uid);
        std::cout << uid << " ~ " << txt << "\n";
        assert(decode57(txt) == uid);
    

打印

f7dd5274-f457-4239-a881-801662d589ad ~ sfitJnfge8vaXnga8kzi7n
3b387615-24ed-4c17-a715-c4413ffac3b5 ~ Vq6uZe6usvSwWftVdBPbYC
3dd64dba-1ff3-40e5-84e3-3fbb0f8b86b9 ~ r5D3drtfrx7322ajzYv82D
b17a848e-5d6b-45d9-ae25-57cfb8a8fec3 ~ petYHah9W3p8GptQ9QJuaZ
a9edc682-147c-4e41-85e2-e06c4ce64086 ~ DFLa6tquGSZvSEi2WE3MFY
2cc90c4a-192f-4b57-bc11-2c322dab2ce0 ~ yyg6AekktrpjdBCjGjsCy9
ac1d94bd-3fbc-46c1-aeec-cdcdc2dd0dd2 ~ dzHCNTADG6R4n3QTjm7XdY
1e3df271-a3c2-4b45-8871-0fde4c2d97e8 ~ tL66L6gqRESaABWsxbrhP7
0d15c1d5-3646-474f-8a5d-989878f12a95 ~ FtnvH2QRENpsFcLXq5zhL4
ececc5dc-cdf1-49f4-b3f7-bfe8697133fd ~ Dkfm7JmgVAuP28JLPDBnAk

¹这些都是基于 RFC4122 随机数的 UUID 的示例,在 Go 中使用 goolge/uuid 时的默认设置

这些编码已经与shortuuid生成的编码进行了验证

【讨论】:

太棒了。谢谢。

以上是关于c++ 创建一个不是 UUID 类型的全局唯一 id的主要内容,如果未能解决你的问题,请参考以下文章

Java中生成的UUID(全局唯一标识符-----(唯一)-------)

什么是UUID?

@TableId注解

简单了解uuid

uuid是啥意思?

如何唯一的标识一台Android设备?