在C中通过位移3个整数来构造关键字

时间:2015-06-09 08:36:36

标签: c key bit-shift

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

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

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位(key + pos)构建isize,我会构建它 使用32 + 16 + 16位(pos + isize + barc)分割最后32位 isizebarc

任何想法如何做到这一点?

3 个答案:

答案 0 :(得分:3)

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

对于这种特殊情况,你应该使用&amp;操作员在将其向上移动之前屏蔽c-> isize的高16位,然后使用&amp;操作符再次掩盖c-> barc的高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

答案 1 :(得分:2)

“管道运算符”实际上是一个按位OR运算符。该代码采用两个(可能是)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位&GT; BARC。有关详情,请参阅here

答案 2 :(得分:1)

我不会这样做。如果你不是自己设计整件事,那就不安全了。但是我们来解释一些事情。

  

我的解释是,密钥是c-> pos,

的最后32位数的组合

一般来说,是的。

  

必须是64位无符号整数,c-> isize,也是64位无符号整数。

没有。您对isizeuint64_t类型的大小一无所知,它会被转换为{{1}},它可能是允许此类演员的任何类型。

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

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

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