簡體   English   中英

散列 C++ 中的原始字節?

[英]Hashing raw bytes in C++?

我想寫一個 function ,它采用兩種類型TU這樣sizeof(T)+sizeof(U)<=8並通過一個接一個地重新解釋它們的字節來獲得uint64_t 但是,這似乎不起作用。 我確信有一種更快、更優雅(和正確)的方法可以做到這一點,但我不知道。 非常感謝任何提示。

#include <cstdint>
#include <iostream>
#include <vector>

template <typename T, typename U>
constexpr auto hash8(T x, U y) {
  static_assert(sizeof(T) + sizeof(U) <= 8);

  uint64_t u = 0;
  uint64_t v = 0;
  auto px = (uint8_t*)&x;
  auto py = (uint8_t*)&y;
  for (auto i = 0; i < sizeof(T); ++i) {
    u |= (uint64_t)px[i];
    u <<= 8;
  }
  for (auto i = 0; i < sizeof(U); ++i) {
    v |= (uint64_t)py[i];
    v <<= 8;
  }

  return u << (sizeof(U) * 8) | v;
}

int main() {
  std::cout << hash8(131, 0) << '\n';
  std::cout << hash8(132, 0) << '\n';
  std::cout << hash8(500, 0) << '\n';
}

最簡單的方法通常是執行memcpy

#include <cstdint>
#include <cstring> // for memcpy

template <typename T, typename U>
auto hash8(T x, U y) {
  static_assert(sizeof(T) + sizeof(U) <= 8);

  uint64_t u = 0;
  char* u_ptr = reinterpret_cast<char*>(&u);
  std::memcpy(u_ptr, &x, sizeof x);
  std::memcpy(u_ptr+sizeof x, &y, sizeof y);
  return u;
}

如果大小參數在編譯時已知(並且相當小),任何體面的編譯器都會將memcpy調用內聯到一些位操作。

如果您確實需要constexpr function,您可以嘗試使用 C++20 中的std::bit_cast (如果任一輸入參數的大小不是 1、2、4 或 8,則可能會很困難)。

由於缺乏細節,我無法解決您代碼中的問題,但我可以提出一個可能更簡單的解決方案。

首先,我建議添加檢查參數對象是否具有唯一的 object 表示。 除非滿足,否則 hash 將毫無意義。

其次, std::memcpy可能會使這更簡單:

template <typename T, typename U>
auto
hash8(T x, U y) noexcept {
    static_assert(sizeof x + sizeof y <= sizeof(std::uint64_t));
    static_assert(std::has_unique_object_representations_v<T>);
    static_assert(std::has_unique_object_representations_v<U>);
    std::uint64_t ret{};
    auto ptr = reinterpret_cast<unsigned char*>(&ret);
    std::memcpy(ptr, std::addressof(x), sizeof x);
    ptr += sizeof x;
    std::memcpy(ptr, std::addressof(y), sizeof y);
    return ret;
}

接下來,我們可以將其推廣到任意數量的 arguments(只要它們適合)和不同的返回類型:

template <typename R = std::uint64_t, typename... Args>
auto
hash(Args... args) noexcept {
    static_assert((sizeof args + ...) <= sizeof(R));
    static_assert((std::has_unique_object_representations_v<Args> && ...));
    static_assert(std::has_unique_object_representations_v<R>);
    R ret{};
    auto ptr = reinterpret_cast<unsigned char*>(&ret);
    (
        (
            std::memcpy(ptr, std::addressof(args), sizeof args),
            ptr += sizeof args
        ), ...
    );
    return ret;
}

需要注意的是,即使對象的大小匹配,這樣的 hash 在不同的系統中也不相同。

PS 使您的 function constexpr 毫無意義,因為您使用常量表達式中不允許的重新解釋轉換。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM