0

我想计算作为字符串传递的结构的哈希值。尽管vlanId值不同,但哈希值仍然相同。该StringHash()函数计算哈希值。我没有为portIdand赋值vsi

#include<stdio.h>
#include <functional>
#include <cstring>

using namespace std;
unsigned long StringHash(unsigned char *Arr)
{
    hash<string> str_hash;

    string Str((const char *)Arr);

    unsigned long str_hash_value = str_hash(Str);
    printf("Hash=%lu\n", str_hash_value);

    return str_hash_value;
}

typedef struct 
{
    unsigned char portId;
    unsigned short vlanId;
    unsigned short vsi;
}VlanConfig; 

int main()
{
    VlanConfig v1;
    memset(&v1,0,sizeof(VlanConfig));
    unsigned char *index = (unsigned char *)&v1 + sizeof(unsigned char);    
        
    v1.vlanId = 10;
    StringHash(index);
    StringHash((unsigned char *)&v1);

    v1.vlanId = 12;
    StringHash(index);
    StringHash((unsigned char *)&v1);
    
    return 0;
}

输出:

Hash=6142509188972423790  
Hash=6142509188972423790  
Hash=6142509188972423790  
Hash=6142509188972423790
4

2 回答 2

2

您将结构的字节传递给期望以零结尾的字符串的函数。好吧,您的结构的第一个字节已经为零,因此您每次都计算相同的哈希值。

现在,这就是原因的解释,但不是您问题的解决方案。将随机字节序列传递给期望以零结尾的字符序列的函数将非常失败,无论您如何操作。

找到另一种方法来散列你的结构。您已经在使用hash<>,为什么不将它用于您的情况:

namespace std
{
    template<> struct hash<VlanConfig>
    {
        std::size_t operator()(VlanConfig  const& c) const noexcept
        {
            std::size_t h1 = std::hash<char>{}(c.portId);
            std::size_t h2 = std::hash<short>{}(c.vlanId);
            std::size_t h3 = std::hash<short>{}(c.vsi);
            return h1 ^ (h2 << 1) ^ (h3 << 2); // or use boost::hash_combine
        }
    };
}

然后你可以这样做:

VlanConfig myVariable;

// fill myVariable

std::cout << std::hash<VlanConfig>{}(myVariable) << std::endl;
于 2021-02-25T09:29:37.403 回答
-1

我不能肯定地说,但很可能你的问题是结构填充。除非明确设置 ot pack 成员并忽略对齐,否则大多数编译器将按如下方式设置结构:

Byte 0: portId
Byte 1: padding
Bytes 2,3: vlanId
Bytes 4,5: vsi

因此,当您计算索引的地址时,它将指向填充字节,该字节始终为零。因此,您总是在散列一个空字符串。

您应该能够通过检查index并将其与vlanId.

- 编辑 -

在考虑了这一点之后,我不得不说,在我极其卑鄙的意见中,这不是获得哈希值的好方法。试图将几个可能在内存中连续或不连续的数值视为 std::string 有太多出错的可能性。

从这样一个事实开始,即使您确实获得了正确的地址,请考虑当您散列两种不同的配置时会发生什么,其中一个vlanId设置为 256,而另一个设置为 512。假设一个小端机器,这两个将有一个零字节作为字符串的第一个字符,所以你又回到了这里。

更糟糕的是,所有四个字节vlanIdvsi非零。在这种情况下,您将立即阅读结构的末尾,并继续阅读,阅读谁知道什么。不可能有好的结局。

一种可能的解决方案是计算数据的大小,并为std::string:使用以下 ctor,string (char const *s, size_t n);其优点是可以将字符串强制为您想要的大小。

于 2021-02-25T09:29:04.717 回答