通过在 C 中移动 3 个整数来构造密钥

constructing key by bit shifting 3 integers in C

我想通过移位操作构造一个由 3 个值组成的键:

根据我的理解,我开始的 C 语句代码通过从某些数据变量构造其键来创建散列 table:

uint64_t key = (uint64_t)c->pos<<32 | c->isize;

我的解释是key是后32位数字的组合 c->pos,必须是 64 位无符号整数,c->isize,也是 64 位无符号整数。

但我不确定是不是这样,也许 | 管道运算符 当应用于位移操作时具有不同的含义。

我接下来要做的是修改key的构造方式和 在变量中包含第三个 c->barc 元素。给定数量 c->barcc->isize 的可能性,我在想 用 32+32 位 (pos+isize) 构建 key,我会构建它 32+16+16 位 (pos+isize+barc) 将最后 32 位拆分为 isizebarc.

知道怎么做吗?

"pipe operator"实际上是按位或运算符。该代码采用两个(大概)32 位整数,其中一个向左移动 32 位并将它们组合在一起。因此,您将获得一个 64 位数字。有关按位运算的详细信息,请参阅 Wiki

如果你想用三个 32 位整数组成你的密钥,那么你显然必须操纵它们以适应 64 位。你可以这样做:

uint64_t key = (uint64_t)c->pos<<32 | (c->isize & 0xFFFF0000) | (c->barc & 0xFFFF);

此代码从 c->pos 中取出 32 位,将它们移入 64 位密钥的高 32 位,然后取出 c->isize 的高 16 位,最后取出 c-的低 16 位>巴克。有关更多信息,请参阅 here

我认为你需要的是 bitmasking 的可靠解释。

对于这种特殊情况,您应该在向上移动之前使用 & 运算符屏蔽掉 c->isize 的高 16 位,然后再次使用 & 运算符屏蔽掉 c-> 的高 48 位巴克

让我们看一些图表。

let
    c->pos          = xxxx_xxxx_....._xxxx
    c->isize        = yyyy_yyyy_....._yyyy
    c->barc         = zzzz_zzzz_....._zzzz
where
    x, y, and z are bits.

note: underscores are to identify groups of 4 bits.

如果我没理解错的话,你想要一个像这样的 64 位数字:

    xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_yyyy_yyyy_yyyy_yyyy_zzzz_zzzz_zzzz_zzzz

对吗?

如您所知,我们通过

获得上面的 32 个 x
                       |-----32 bits of pos----|---32 0 bits--|
(uint64_t)c->pos<<32 = xxxx_xxxx_...._xxxx_xxxx_0000_...._0000

现在,我们要按位或使用以下内容:

|----------32 0 bits----|
0000_0000_...._0000_0000_yyyy_yyyy_yyyy_yyyy_0000_0000_0000_0000

为了得到那个数字,我们这样做:

((c->isize & 0xffff) << 16)
because:
c->isize & 0xffff gives 
    yyyy_yyyy_yyyy_yyyy_yyyy_yyyy_yyyy_yyyy
&   0000_0000_0000_0000_1111_1111_1111_1111
---------------------------------------------
    0000_0000_0000_0000_yyyy_yyyy_yyyy_yyyy

and then we shift it left by 16 to get 

|--------32 0 bits------|
0000_0000_...._0000_0000_yyyy_yyyy_yyyy_yyyy_0000_0000_0000_0000

现在,最后一部分,

|-------48 0 bits-------|
0000_0000_...._0000_0000_zzzz_zzzz_zzzz_zzz

的简单明了的结果
(c->barc & 0xffff) = 

    zzzz_zzzz_zzzz_zzzz_zzzz_zzzz_zzzz_zzzz
&   0000_0000_0000_0000_1111_1111_1111_1111
-------------------------------------------------
    0000_0000_0000_0000_zzzz_zzzz_zzzz_zzzz

所以我们将所有这些表达式和按位或放在一起。

uint64_t key = ((uint64_t)c->pos << 32) | ((c->isize & 0xffff) << 16) 
               | (c->barc & 0xffff);

if we diagram it out, we see
    xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_0000_0000_0000_0000_0000_0000_0000_0000
    0000_0000_0000_0000_0000_0000_0000_0000_yyyy_yyyy_yyyy_yyyy_0000_0000_0000_0000
or  0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_zzzz_zzzz_zzzz_zzzz
-----------------------------------------------------------------------------------
    xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_yyyy_yyyy_yyyy_yyyy_zzzz_zzzz_zzzz_zzzz

我不会这样做。如果你不是自己设计整个东西,那是不安全的。但是让我们解释一些事情。

My interpretation is that key is a combination of the last 32 digits of c->pos,

一般来说,是的。

which must be a 64 bit unsigned integer, and c->isize, also a 64bit unsigned integer.

没有。您对 posisize 类型的大小一无所知,它被强制转换为 uint64_t 它可能是任何允许此类强制转换的类型。

我敢打赌这两个值都是 32 位的。第一个值被转换为 64 位类型,因为位移等于或大于类型的宽度是未定义的行为。所以为了安全起见,它被加宽了。

该代码可能会将两个 32 位值打包到一个 64 位值中,否则会丢失信息。

此外,如果它想从重叠的值构造键,它很可能会使用 xor 而不是 or。你的方法不是一个好方法,除非你确切地知道你在做什么。你应该找出你的操作数是什么类型,然后从中选择一种创建键的方法。