在不使用boost库的情况下,我该如何在C++中生成UUID?

52

我想为我的应用生成UUID,以区分每个应用程序的安装。 我想使用C ++生成此UUID,而不需要boost库支持。 如何使用其他开源库生成UUID?

注意:我的平台是Windows。


2
Qt - Angew is no longer proud of SO
2
在Windows上,您可以使用rpc.h中的UuidCreate。例如:http://nogeekhere.blogspot.in/2008/07/how-to-generate-uuid-guid-in-c.html - Favonius
1
加一,"不使用boost" - Johan
9个回答

27

如果你正在使用现代化的C++,那么这将非常合适。

#include <random>
#include <sstream>

namespace uuid {
    static std::random_device              rd;
    static std::mt19937                    gen(rd());
    static std::uniform_int_distribution<> dis(0, 15);
    static std::uniform_int_distribution<> dis2(8, 11);

    std::string generate_uuid_v4() {
        std::stringstream ss;
        int i;
        ss << std::hex;
        for (i = 0; i < 8; i++) {
            ss << dis(gen);
        }
        ss << "-";
        for (i = 0; i < 4; i++) {
            ss << dis(gen);
        }
        ss << "-4";
        for (i = 0; i < 3; i++) {
            ss << dis(gen);
        }
        ss << "-";
        ss << dis2(gen);
        for (i = 0; i < 3; i++) {
            ss << dis(gen);
        }
        ss << "-";
        for (i = 0; i < 12; i++) {
            ss << dis(gen);
        };
        return ss.str();
    }
}

14
值得注意的是,这个输出格式类似于GUID,但不足以被视为“唯一的”GUID。std::mt19937拥有32位的随机性,即40亿种组合。一个真正的GUID具有128位的随机性,即3E38种组合。一个真正的GUID将比它(三十多亿)更加随机。使用mt19937->mt19937_64可以改善情况,它具有64位的随机性,即1.8E19种组合,但在随机性期望方面仍然不能被视为GUID。 - Paul Gilmore
一个问题:32位的随机性 + 32位的随机性 + .... + 32位的随机性不等于128位的随机性吗? - Raul Luna
7
@RaulLuna 不行,因为这是伪随机数生成器,所以所有后续调用都依赖于先前的调用。就像从 int16 制作 SHA256 仍然会产生 65,000 个唯一哈希值,而不是 2 ** 256。std::mt19937 包含更多位状态,但这取决于初始状态,因此子序列非常不清楚。真正的 UUID 在唯一性方面要可靠得多。 - Konstantine Kozachuck
11
PRNG(伪随机数生成器)有足够大的状态(19937位),但完全由random_device (rd())生成的32位值进行种子,因此该函数只能生成2^32个可能的uuid。不要使用此答案或类似答案,否则可能会引入安全问题。请参见此问题,已经被Downvote。 - Alba Mendez

19

如评论中所述,您可以使用UuidCreate函数。

#pragma comment(lib, "rpcrt4.lib")  // UuidCreate - Minimum supported OS Win 2000
#include <windows.h>
#include <iostream>

using namespace std;

int main()
{
    UUID uuid;
    UuidCreate(&uuid);
    char *str;
    UuidToStringA(&uuid, (RPC_CSTR*)&str);
    cout<<str<<endl;
    RpcStringFreeA((RPC_CSTR*)&str);
    return 0;
}

#Yuval,我应该下载rpcrt4.lib并将该库文件保存在lib文件夹中吗?否则rpcrt4.lib是否可用于Windows。抱歉问这样愚蠢的问题。 - PURE
@PURE 这个库已经随着 Visual Studio 的安装一起包含了。 - Yuval
或者使用CoCreateGuid,它是UuidCreate的包装器。 - gast128
请注意,为了链接rpcrt4.lib,您必须打开项目属性,转到“配置属性”->“链接器”->“命令行”,然后在“附加选项”框中键入Rpcrt4.lib。 - BinaryNate
4
对我而言,需要使用 #include <rpc.h>(而不是 #include <windows.h> - user4851

13

如果你只想要一些随机内容,我写了这个小函数:

string get_uuid() {
    static random_device dev;
    static mt19937 rng(dev());

    uniform_int_distribution<int> dist(0, 15);

    const char *v = "0123456789abcdef";
    const bool dash[] = { 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 };

    string res;
    for (int i = 0; i < 16; i++) {
        if (dash[i]) res += "-";
        res += v[dist(rng)];
        res += v[dist(rng)];
    }
    return res;
}

3
不保证,但中彩后被雷劈的可能性比发生碰撞要大。 - CaptainCodeman
感谢@CaptainCodeman。已经可以与标准库一起使用了。完美。 - Luc-Olivier

7

ossp-uuid库可以生成UUID并且有C++绑定。

看起来使用非常简单:

#include <uuid++.hh>
#include <iostream>

using namespace std;

int main() {
        uuid id;
        id.make(UUID_MAKE_V1);
        const char* myId = id.string();
        cout << myId << endl;
        delete myId;
}

请注意,它分配并返回一个C风格的字符串,调用代码必须释放内存以避免泄漏。
另一种可能性是libuuid,它是util-linux包的一部分,可从ftp://ftp.kernel.org/pub/linux/utils/util-linux/获取。任何Linux机器都已安装它。它没有C++ API,但仍可以使用C API从C++中进行调用。

2
关于调用uuid的string()函数,需要注意一点,这会分配必须由调用代码释放的内存!在上面的答案中,调用id.string()返回一个指向新分配内存的char*,而不是一个漂亮的std::string(通过析构函数/RAII管理其内存)。因此,上述代码存在内存泄漏。更好的做法是设置char* str = id.string(),然后在使用完毕后调用delete删除str。 - jCuga
@jCuga 天啊,我甚至没有注意到!谢谢,我已经更新了答案。 - harmic

6

2021年,我建议使用单头文件库stduuid。它跨平台且不会引入任何不必要的依赖。

从项目的github页面下载uuid.h,然后可以使用以下示例:

#include <iostream>
#include <string>

#define UUID_SYSTEM_GENERATOR
#include "uuid.h"

int main (void) {
    std::string id = uuids::to_string (uuids::uuid_system_generator{}());
    std::cout << id << std::endl;
}

请查看该项目的 Github 页面,了解更多有关各种选项和生成器的详细信息和文档。


这个仓库的测试通过了吗? - Djvu
这个库似乎使用了std::mt19937,因此我认为它仍然存在已经在这个问题上讨论过的“足够唯一”的问题。 - ScaryAardvark
这个库是一个建议添加到stdlib的实现,因此具有非常全面的API。它需要C++17。 - Fred Schoen

2

传统上,UUID只是机器的MAC地址与自西方采用公历以来的100纳秒间隔数拼接而成。因此,编写一个C++class执行此操作并不太困难。


1
但是我需要基于随机数生成UUID(类型4),#Paul。我无法使用C ++中可用的普通rand()函数。这就是为什么我要寻找库文件的原因。 - PURE
1
有几个UUID的版本和变体;你的答案只涵盖了版本1。 - Angew is no longer proud of SO
1
@user3732956:如果您要生成随机UUID,为什么不能使用rand()或其他(伪)随机函数呢?请问原因是什么? - DevSolar
嗯,要使用伪随机函数,我认为应该去库文件,对吧。这就是为什么我更喜欢直接使用UUID库文件的原因。 - PURE
1
这种UUID(类型1)的使用已被放弃,因为它会泄漏PII,转而采用不泄漏PII的UUIDs。 - JoeG
C++11有<random>,比rand()好得多。 - Basile Starynkevitch

0
Linux实用程序libuuid可以帮助您完成此任务。以下是一个示例,用于填充UUID ROS消息。任何其他16字节的缓冲区也可以使用。使用非常简单:
#include "uuid/uuid.h"

...

unique_identifier_msgs::msg::UUID uuid;
uuid_generate(uuid.uuid.data());

同样的API也适用于Mac。这个cmake代码展示了在哪里链接https://github.com/malaterre/GDCM/blob/master/CMake/FindUUID.cmake
对于需要覆盖所有三个平台的情况,此问题的其他解决方案解释了如何使用Windows本地API。 文档
man 3 uuid_generate

或在线 https://github.com/util-linux/util-linux/blob/master/libuuid/man/uuid_generate.3.adoc

许可证

宽松,参见 https://github.com/util-linux/util-linux/blob/master/libuuid/src/uuid.h 的头文件

为什么要这个新答案

扩展 @harmic 的答案,因为它提到了两个解决方案,后者很容易被忽略。


0

这段代码对我来说可行 :)

#pragma comment(lib, "rpcrt4.lib") 
#include <windows.h>
#include <rpcdce.h>
/*
* Generate a Universal Unique Identifier using windows api.
* Note: throw exceptions if uuid wasn't created successfully.
*/
std::string generate_uuid()
{
    UUID uuid;
    RPC_CSTR  uuid_str;
    std::string uuid_out;

    if (UuidCreate(&uuid) != RPC_S_OK)
        std::cout << "couldn't create uuid\nError code" << GetLastError() << std::endl;

    if (UuidToStringA(&uuid, &uuid_str) != RPC_S_OK)
        std::cout << "couldn't convert uuid to string\nError code" << GetLastError() << std::endl;

    uuid_out = (char*)uuid_str;
    RpcStringFreeA(&uuid_str);
    return uuid_out;
}

-1
你可以使用我开发的 rst C++ 库来完成这个任务:
#include "rst/guid/guid.h"

std::string guid = rst::Guid().AsString();

// Performs no allocations.
std::cout << rst::Guid().AsStringView().value() << std::endl;

4
你提供的 GitHub 项目似乎是你自己创建的。如果是这样的话,你必须明确披露这个事实,否则你的帖子可能会被认为是垃圾邮件。 - Adrian Mole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接