c - 这种散列任何通用对象的方法是否正确?

标签 c hashcode void-pointers

使用 OpenJDK 的 hashCode ,我尝试在 C 中实现一个通用的哈希例程:

U32 hashObject(void *object_generic, U32 object_length) {
    if (object_generic == NULL) return 0;

    U8 *object = (U8*)object_generic;
    U32 hash = 1;

    for (U32 i = 0; i < object_length; ++i) {
//      hash = 31 * hash + object[i]; // Original prime used in OpenJDK
        hash = 92821 * hash + object[i]; // Better constant found here: https://stackoverflow.com/questions/1835976/what-is-a-sensible-prime-for-hashcode-calculation
    }

    return hash;
}

我的想法是,我可以将指针传递给任何 C 对象(原始类型、结构、数组等),并且该对象将被唯一地散列。然而,由于这是我第一次做这样的事情,我想问一下 - 这是正确的方法吗?有什么我需要注意的陷阱吗?

最佳答案

绝对有陷阱。例如,下面的程序使用您的函数,在 gcc -O0 下为每个等效对象打印不同的值(并且每次编译时打印不同的值):

#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

struct foo {
    char c;
    int i;
};

static uint32_t hashObject(void const* object_generic, uint32_t object_length) {
    if (object_generic == NULL) return 0;

    uint8_t const* object = (uint8_t const*)object_generic;
    uint32_t hash = 1;

    for (uint32_t i = 0; i < object_length; ++i) {
        hash = 92821 * hash + object[i];
    }

    return hash;
}

int main() {
    struct foo a[2];

    a[0].c = 'A';
    a[0].i = 1;

    a[1].c = 'A';
    a[1].i = 1;

    _Static_assert(
        sizeof(struct foo) == offsetof(struct foo, i) + sizeof(int),
        "struct has no end padding"
    );

    printf("%d\n", hashObject(&a[0], sizeof *a));
    printf("%d\n", hashObject(&a[1], sizeof *a));

    return EXIT_SUCCESS;
}

发生这种情况是因为填充可以包含任何内容。

关于c - 这种散列任何通用对象的方法是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42709071/

相关文章:

c - C 中带有 void 指针的动态类型变量(最终动态类型转换)

c++ - 在 extern C 声明中,对象和 void 指针可以互换吗?

Hibernate:什么时候需要实现 equals() 和 hashCode(),如果需要,如何实现?

java - 这是 hashCode() 的一个很好的实现吗?

c++ - 将地址转换为长变量结果值?

c++ - 我可以通过链接静态库来构建共享库吗?

c - C 中的双 For 循环语法

c - 严格的别名和覆盖继承

c - 如何实现字数统计 bash shell

java - 复合 id 类的 hashCode() 和 equals() 方法