Bitshift - 需要解释才能理解代码

时间:2014-06-30 12:13:57

标签: c++ c bit-manipulation bit-shift

我想知道这个功能实际上是做什么的。 根据我的理解,它应该返回pSrc [1]。

那么为什么它会将左移pSrc [0]加扰8位,这会将这8位清零。 当这些零与pSrc [1]进行“或”运算时,pSrc [1]不会受到影响,因此无论如何都会得到pSrc [1],就像从未发生过按位OR一样。

/*
* Get 2 big-endian bytes.
*/
INLINE u2 get2BE(unsigned char const* pSrc)
{
    return (pSrc[0] << 8) | pSrc[1];
}

此功能来自dalvik虚拟机的源代码。 https://android.googlesource.com/platform/dalvik/+/android-4.4.4_r1/vm/Bits.h

更新

好的,现在我得到了感谢这里的所有答案。

(1)pSrc [0]最初是无符号字符(1字节)。

(2)当使用int类型的文字8左移(pSrc [0]&lt;&lt; 8)时,pSrc [0]因此被int提升为signed int(4字节)。< / p>

(3)pSrc [0]的结果&lt;&lt; 8是pSrc [0]中感兴趣的8位被移位到signed int的4个字节的第二个字节,从而在其他字节(第1,第3和第4个字节)中留下零。

(4)当它是ORed(步骤(3)的中间结果| pSrc [1])时,pSrc [1]然后被int提升为signed int(4字节)。

(5)(步骤(3)| pSrc [1]的中间结果)的结果以两个最高有效字节中的所有零的形式留下前两个最低有效字节。

(6)返回前两个最低有效字节,通过将结果作为u2类型返回来获得2个大端字节。

3 个答案:

答案 0 :(得分:8)

对于像这样的算术运算,unsigned char通过名为整数促销的流程进行转换。

C ++ 11 - N3485§5.8[expr.shift] / 1:

  

操作数应为整数或无范围的枚举类型,并执行整体促销。结果的类型是提升的左操作数的类型。

§13.6[over.built] / 17:

  

对于每对提升的整数类型L和R,存在形式

的候选运算符函数
LR operator%(L , R );
LR operator&(L , R );
LR operator^(L , R );
LR operator|(L , R );
L operator<<(L , R );
L operator>>(L , R );
     

其中LR是类型L和R之间通常的算术转换的结果。

完成整体促销活动时(§4.5[conv.prom] / 1):

  

除bool,char16_t,char32_t或wchar_t之外的整数类型的整数转换的整数转换   如果int可以表示all,则rank(4.13)小于int的rank可以转换为int类型的prvalue   源类型的值;否则,源prvalue可以转换为unsigned类型的prvalue   中间体

通过整体促销,unsigned char将提升为int。另一个操作数已经是int,因此不会对其进行类型更改。然后返回类型也变为int

因此,你所拥有的是第一个unsigned char位向左移位,但仍然在现在更大的int,然后是最后的第二个unsigned char

您会注意到operator|的返回类型是两个操作数之间通常算术转换的结果。此时,这些是来自班次的int和第二个unsigned char

此转换定义如下(§5[expr] / 10):

  

许多期望算术或枚举类型操作数的二元运算符会导致转换和产生   结果类型以类似的方式。目的是产生一个通用类型,它也是结果的类型。   这种模式称为通常的算术转换,其定义如下:
  ...
  否则,应对两个操作数执行整体促销(4.5)。然后是以下   规则应适用于推广的操作数:
  ...
  如果两个操作数具有相同的类型,则不需要进一步转换。

由于在此之前被提升的LR已经int,促销会使它们保持不变,因此表达式的整体返回类型为int然后转换为u2,无论发生什么。

答案 1 :(得分:4)

没有操作(类型转换除外) unsigned char。在任何操作之前,积分促销 发生,将unsigned char转换为int。所以 操作正在移动int左,而不是unsigned char

答案 2 :(得分:3)

C11 6.5.7按位移位运算符

  

对每个操作数执行整数提升。类型   结果是提升的左操作数。如果值为   右操作数是负数或大于或等于   提升左操作数的宽度,行为未定义。

     

E1的结果&lt;&lt; E2是E1左移E2位位置;腾出的位充满了   零。如果E1具有无符号类型,则结果的值为E1×2E2,模数减少   比结果类型中可表示的最大值多一个。 如果E1已签名   类型和非负值,E1×2E2在结果类型中可表示,那就是   结果价值;否则,行为未定义。

因此pSrc[0]整数提升为int。文字8已经是int,因此不会进行整数提升。通常的算术转换不适用于移位运算符:它们是一种特殊情况。

由于原始变量是一个unsigned char左移8位,我们也遇到了“E1”(我们的提升变量)被签名的问题,并且可能无法在结果类型中表示结果,如果这是一个16位系统,则会导致未定义的行为。

用简单的英语:如果你将某些东西转移到有符号变量的符号位,就会发生任何事情。一般来说:依赖隐式类型的促销是糟糕的编程和危险的做法。

您应该将代码修改为:

((unsigned int)pSrc[0] << 8) | (unsigned int)pSrc[1]