C中的哈希宏定义

时间:2019-03-03 09:15:37

标签: c

这里有一个函数样式宏,它计算哈希键,但是我不能完全理解它,如下所示:

#define __jhash_mix(a, b, c)            \
{                       \
    a -= c;  a ^= rol32(c, 4);  c += b; \
    b -= a;  b ^= rol32(a, 6);  a += c; \
    c -= b;  c ^= rol32(b, 8);  b += a; \
    a -= c;  a ^= rol32(c, 16); c += b; \
    b -= a;  b ^= rol32(a, 19); a += c; \
    c -= b;  c ^= rol32(b, 4);  b += a; \
}

请让我知道将返回什么值以及如何处理它。

2 个答案:

答案 0 :(得分:2)

您可能是从jhash.h: Jenkins hash support

获得此定义的

正如评论在前一个链接上所说,它可逆地混合3个32位值,值 a,b c 来自一个密钥,该密钥被视为32位值的序列,最终目标是计算密钥的哈希值。

Rotate和xor在计算哈希中非常常见,它们还具有可逆的优点。


如果我使用部分代码为 my 案例添加更多个人定义:

#include <stdlib.h>
#include <time.h>
#include <stdio.h>

/* some personal definition for my case to make it working */
#define u32 unsigned int
#define u8 unsigned char
#define __get_unaligned_cpu32(k) (*k)

unsigned rol32(unsigned v, int n)
{
  return (v << n) | (v >> ((-n) & 0x1F));
}

/* codes from hash.h: Jenkins hash support.
 *
 * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
 * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
 */

/* __jhash_mix -- mix 3 32-bit values reversibly. */
#define __jhash_mix(a, b, c)                        \
{                                                \
        a -= c;  a ^= rol32(c, 4);  c += b;        \
        b -= a;  b ^= rol32(a, 6);  a += c;        \
        c -= b;  c ^= rol32(b, 8);  b += a;        \
        a -= c;  a ^= rol32(c, 16); c += b;        \
        b -= a;  b ^= rol32(a, 19); a += c;        \
        c -= b;  c ^= rol32(b, 4);  b += a;        \
}

/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
#define __jhash_final(a, b, c)                        \
{                                                \
        c ^= b; c -= rol32(b, 14);                \
        a ^= c; a -= rol32(c, 11);                \
        b ^= a; b -= rol32(a, 25);                \
        c ^= b; c -= rol32(b, 16);                \
        a ^= c; a -= rol32(c, 4);                \
        b ^= a; b -= rol32(a, 14);                \
        c ^= b; c -= rol32(b, 24);                \
}

/* An arbitrary initial parameter */
#define JHASH_INITVAL                0xdeadbeef

/* jhash - hash an arbitrary key
 * @k: sequence of bytes as key
 * @length: the length of the key
 * @initval: the previous hash, or an arbitray value
 *
 * The generic version, hashes an arbitrary sequence of bytes.
 * No alignment or length assumptions are made about the input key.
 *
 * Returns the hash value of the key. The result depends on endianness.
 */
static inline u32 jhash(const void *key, u32 length, u32 initval)
{
        u32 a, b, c;
        const u8 *k = key;

        /* Set up the internal state */
        a = b = c = JHASH_INITVAL + length + initval;

        /* All but the last block: affect some 32 bits of (a,b,c) */
        while (length > 12) {
                a += __get_unaligned_cpu32(k);
                b += __get_unaligned_cpu32(k + 4);
                c += __get_unaligned_cpu32(k + 8);
                __jhash_mix(a, b, c);
                length -= 12;
                k += 12;
        }
        /* Last block: affect all 32 bits of (c) */
        switch (length) {
        case 12: c += (u32)k[11]<<24;        /* fall through */
        case 11: c += (u32)k[10]<<16;        /* fall through */
        case 10: c += (u32)k[9]<<8;        /* fall through */
        case 9:  c += k[8];                /* fall through */
        case 8:  b += (u32)k[7]<<24;        /* fall through */
        case 7:  b += (u32)k[6]<<16;        /* fall through */
        case 6:  b += (u32)k[5]<<8;        /* fall through */
        case 5:  b += k[4];                /* fall through */
        case 4:  a += (u32)k[3]<<24;        /* fall through */
        case 3:  a += (u32)k[2]<<16;        /* fall through */
        case 2:  a += (u32)k[1]<<8;        /* fall through */
        case 1:  a += k[0];
                 __jhash_final(a, b, c);
        case 0: /* Nothing left to add */
                break;
        }

        return c;
}

#define N 32

int main()
{
  int k[32];
  size_t i;

  srand(time(0));

  printf("jhash({");

  for (i = 0; i != N; ++i) {
    k[i] = rand();
    printf("%d ", k[i]);
  }

  printf("}, %u, 0) = %u\n", N, jhash(k, N, 0));
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra k.c
pi@raspberrypi:/tmp $ ./a.out
jhash({725625346 2051442142 1165233932 1356547768 2099014845 266019399 528918070 18604707 1945148507 987748948 1335740895 332797747 1690673992 2098399251 1687576619 286743973 2002511209 1997615319 887418158 1218108826 1451009818 973285977 2028050363 1116200465 863906896 1573231493 1035506113 1283577784 928643781 74360164 191441086 1654269127 }, 32, 0) = 1693699835
pi@raspberrypi:/tmp $ ./a.out
jhash({1500372397 800038188 1822383935 2049924247 1967907533 1822952097 1311149758 1738252197 464832103 1177755638 296710542 694221671 414698890 78801632 1686474026 1285412744 264383868 1512129910 242686348 514308142 557986701 1643746510 341957038 1943957666 304144553 484844558 449494178 1729050684 1161649732 1866984013 472090176 514538481 }, 32, 0) = 1130358
pi@raspberrypi:/tmp $ ./a.out
jhash({122835781 612581003 328765017 1664431043 1825042737 154150284 1014172891 1296418362 1125874777 1361929618 1388631300 1047417778 1279955676 1261053435 600697914 129834773 1724943228 1012276842 1738014852 1931963584 1793760158 1232153606 1847243743 600168910 808588272 1509948749 1980278411 1089542038 1356188813 1473345525 739126939 1479024594 }, 32, 0) = 843972389

答案 1 :(得分:0)

宏执行文本替换。这意味着它仅替换您在定义内以abc的形式给出的内容。您可以手动执行相同操作,它应该为您提供生成的代码。

注意:

  • 宏的运行没有任何语法检查,类型检查或其他健全性检查,这就是为什么它们通常不被接受的原因。
  • 此代码的实际操作也取决于您提供给它的内容。我的回答并没有说明正是由于这个原因该如何工作。这取决于此宏无法控制的事情。
  • 最好将此代码编码为内联函数,它提供类型检查并通常提供一些约束,进而提供保证。
  • 在这里大概无关紧要,但是这个宏甚至是有问题的,因为它使用了一个为编译器和实现保留的符号(双,连续的下划线)。我不确定确切的用语,但是它会导致程序格式错误或导致未定义的行为,但是“ buggy”总结得很好。那是使此代码不好的另一件事。