0

我正在调试一个函数hashKey。问题是它在不同平台、windows/win ce、mac os、android下对相同的输入产生不同的结果。这是代码:

unsigned long hashKey(const char *name,size_t len)
{
    unsigned long h=(unsigned long)len;
    size_t step = (len>>5)+1;
    for(size_t i=len; i>=step; i-=step)
        h = h ^ ((h<<5)+(h>>2)+(unsigned long)name[i-1]);
    return h;
}

这是我使用的测试程序:

int main()
{
    char word[] = { 0xE6, 0xBE, 0xB3, 0xE9, 0x96, 0x80, 0xE7, 0x89, 0xB9, 0xE5, 
        0x88, 0xA5, 0xE8, 0xA1, 0x8C, 0xE6, 0x94, 0xBF, 0xE5, 0x8D, 
        0x80, 0x2E, 0x70, 0x6E, 0x67, 0x00};
    // for those who are interested in what the value of variable means, it means
    // "澳門特別行政區.png"

    unsigned int val = hashKey(word, strlen(word));
    printf("hash key for [%s] is [%d].\n", word, (unsigned int)val);
}

长度为25,输入值相同,但返回值不同:

在android中是648,在win ce中是96,就是期望值。

我不知道为什么。任何帮助表示赞赏。提前致谢!

更多信息:

  1. 不同的值在循环中的几次交互后开始,由h>>2. 所以一开始,价值观是一样的。

  2. 似乎输入 ansi 字符没有这样的问题。

2013 年 5 月 3 日解决(感谢 Yojimbo 的建议)。

unsigned long hashKey(const char *name,size_t len)
{
    unsigned long h=(unsigned long)len;
    size_t step = (len>>5)+1;
    for(size_t i=len; i>=step; i-=step)
    {
        unsigned long charVal = (unsigned long)name[i-1];
        if (charVal >= 0x00000080)
            charVal = charVal | 0xffffff80;
        h = h ^ ((h<<5 & 0xffffffe0)+(h>>2 & 0x3fffffff) + charVal);
    }
    return h;
}
4

3 回答 3

1

也许有些编译器将“char”视为已签名,而其他编译器则没有?尝试改变

h = h ^ ((h<<5)+(h>>2)+(unsigned long)name[i-1]);

h = h ^ ((h<<5)+(h>>2)+(unsigned long)(name[i-1] & 0xff));

此外,按位右移(您的 h>>2)可能会扩展符号位或不扩展符号位,具体取决于编译器和机器指令集的异想天开。

于 2013-04-28T02:35:11.410 回答
0

您正在使用按位移位运算符。您确定所讨论的处理器上的字节顺序相同吗?x86 使用小端,ARM 可以是大端或小端。

此外,int 和 long 的大小可能不同。C++ 中唯一的规则是 char <=short <=int <=long <= long long。确切的大小没有定义并且可以改变。64 位处理器通常比 32 位处理器具有更大的整数和长整数。

于 2013-04-28T02:36:34.313 回答
0

您假设 int 和 long 的大小是固定的,但它们不是:它们因平台而异。https://en.wikipedia.org/wiki/Long_integer#Long_integer

当我在 64 位机器上运行该代码时,我得到了一个很大的负数。尝试包含 stdint.h 并在任何重要的地方使用显式大小的类型,如“uint32_t”。(即遍历数组的循环可以是“int”,但位操作应该是固定大小的类型。)

于 2013-04-28T02:36:38.833 回答