在 C++ 中,哈希字符串值导致 Linux 与 Windows 上的不同输出

Hashing string values results in different outputs on Linux vs Windows in C++

我正在尝试散列单个 std::stringstd::vector<std::string> 值。我正在关注 cppreference and boost 中的示例。当代码编译时 运行 on Windows vs Linux,我得到不同的结果。

MyHasher.h的头文件如下。

class MyHasher {
 private:
  MyHasher() = delete;
 public:
  static std::size_t hash(std::vector<std::string> ids);
  static std::size_t hash(std::string s);
  static void hashCombine(std::size_t &seed, std::size_t value);
};

CPP文件MyHasher.cpp如下

std::size_t MyHasher::hash(std::vector<std::string> ids) {
  std::size_t seed = 0;
  for (auto id : ids) {
    std::size_t h = std::hash<std::string>{}(id);
    hashCombine(seed, h);
  }
  return seed;
}
std::size_t MyHasher::hash(std::string s) {
  std::size_t seed = 0;
  std::size_t h = std::hash<std::string>{}(s);
  hashCombine(seed, h);
  return seed;
}
void MyHasher::hashCombine(std::size_t &seed, std::size_t value) {
  seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
}

示例程序然后运行如下。

int main() {
  std::cout << std::to_string(MyHasher::hash("0")) << " | 0" << std::endl;
  std::cout << std::to_string(MyHasher::hash(std::vector<std::string>{"0"})) << " | 0" << std::endl;
  std::cout << std::to_string(MyHasher::hash(std::vector<std::string>{"0", "1"})) << " | 0 1" << std::endl;
  return 0;
}

在Linux(g++ 7.4.0)上,输出如下。

2297668036269395695 | 0
2297668036269395695 | 0
10545066640295778616 | 0 1

在Windows(Visual Studio Community 2019, MSVC-14.0)上,输出如下。

12638135526163551848 | 0
12638135526163551848 | 0
1964774108746342951 | 0 1

关于这个差异有什么想法吗?

我真正想要的是一种始终生成依赖于输入但跨平台且宽度固定的唯一哈希输出的方法。据说宽度并不重要,但只要宽度相同,无论输入如何。

在文档中。在 std::hash 中,明确提到:

The actual hash functions are implementation-dependent

Hash functions are only required to produce the same result for the same input within a single execution of a program;

我有点不确定哈希函数总是returns相同输入的相同哈希值。我在谷歌上搜索了一下,但没有找到我敢于展示的内容。

假设 MS VC++ 和 g++ 的标准库可能是不同的实现,不能期望为相同的输入产生相同的散列。

仔细阅读引用的第二部分,您甚至不能指望同一个程序在不同进程(例如,启动、退出和再次启动时)的相同输入会产生相同的哈希值。


Cryptographic hash functions 可能是一个解决方案:

  • it is deterministic, meaning that the same message always results in the same hash
  • it is quick to compute the hash value for any given message
  • it is infeasible to generate a message that yields a given hash value
  • it is infeasible to find two different messages with the same hash value a small change to a message should change the hash value so extensively that the new hash value appears uncorrelated with the old hash value (avalanche effect)

Checksums 与哈希函数有关。对于校验和,必须要求对相同的输入产生相同的输出(可靠)。

所以,基于哈希函数的校验和实现也应该符合OP的要求。

SSE: Which hashing algorithm shoud I use for a safe file checksum? recommends SHA256 or SHA512 的已接受答案。

这让我想起了我最近听说 git uses a variation of SHA-1 but 在我看来这与(我假设)OP 可能具有的用例相似。