1

我正在尝试以这种方式从boost::compute::detail::sha1生成boost::uuids::uuid :

#include <iostream>
#include "boost/uuid/uuid.hpp"
#include "boost/uuid/uuid_io.hpp"
#include "boost/uuid/string_generator.hpp"
#include "boost/compute/detail/sha1.hpp"

int main(int argc, char* argv[])
{
    try
    {
        boost::compute::detail::sha1 sha1("b888e35f9edf3794760392e1066d69-f43d-452e-8475-a09bae9a2e8500000000-0000-0000-0000-000000000000");
        std::string str = sha1;
        boost::uuids::uuid uuid = boost::uuids::string_generator()(str); // ERROR HERE!!
    }
    catch (std::exception& e)
    {
        std::cerr << "Error occurred: " << e.what() << std::endl;
    }

    return 0;
}

但是此代码因错误而失败Error occurred: invalid uuid string(见上文)

我正在使用 Visual Studio 2017,Boost 1.67

我的错误在哪里?如何从 boost::compute::detail::sha1 生成 boost::uuids::uuid

PS:该代码适用于以前的 boost 版本。

4

1 回答 1

1

从任意字符串的 SHA1 哈希中获取 UUID 的正确且受支持的方法如下:

#include <string_view>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/name_generator_sha1.hpp>

boost::uuids::uuid uuid_from_string(std::string_view const input) {
    static constexpr boost::uuids::uuid ns_id{}; // †null root, change as necessary
    return boost::uuids::name_generator_sha1{ns_id}(input.data(), input.size());
}

Online Demo

std::string_view用于展示;如果这不适合您,请使用std::stringor或其他适当的东西。)char const*

虽然这是正确的方法,但有两个重要的注意事项:

  1. 根据 RFC 4122,您需要为您的 UUID 提供命名空间;基本上这是你的 SHA1 哈希的盐。DNS 名称、URL、ISO OID 和 X.500 可分辨名称有预定义的名称空间,但您的输入似乎与您需要定义的任何名称都不匹配;如标记 † 的行所示,此处使用空命名空间进行说明。可以在这个 SO 答案中找到对 UUID 命名空间的更详细说明:生成 v5 UUID。什么是名称和命名空间?

  2. 此代码的输出将与您问题中代码的输出完全不同;如果 您需要输出匹配旧代码,您可以执行以下操作:

    #include <cstring>
    #include <string_view>
    #include <boost/endian/conversion.hpp>
    #include <boost/uuid/uuid.hpp>
    #include <boost/uuid/detail/sha1.hpp>
    
    boost::uuids::uuid uuid_from_string_old(std::string_view const input) {
        boost::uuids::detail::sha1::digest_type digest;
        {
            boost::uuids::detail::sha1 h;
            h.process_bytes(input.data(), input.size());
            h.get_digest(digest);
        }
    
        boost::uuids::uuid ret;
        auto p = ret.begin();
        for (std::size_t i{}; i != 4; p += 4, ++i) {
            auto const d = boost::endian::native_to_big(digest[i]);
            std::memcpy(p, &d, 4);
        }
        return ret;
    }
    

    Online Demo

    这会产生相同的输出,从使用 Boost 1.65.1 的旧代码的演示中可以看出。这违背了我评论过的从不直接使用别人的detail命名空间的政策,但除非你能找到神奇的命名空间 id(如果存在的话),这是我知道的唯一使用 Boost 的方法。注意,这修复了用于大端机器的旧 Boost 代码中的错误;如果您需要保留该错误,请将调用更改boost::endian::native_to_big为调用boost::endian::endian_reverse

于 2018-07-14T00:22:22.250 回答