繁体   English   中英

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

[英]Bitshift - Need explanation to understand the code

我想知道这个功能实际上是什么。 根据我的理解,它应该返回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] << 8)时,pSrc [0]因此被int提升为signed int(4字节)。

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

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

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

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

对于像这样的算术运算, 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):

如果int可以表示源类型的所有值,则除了bool,char16_t,char32_t或wchar_t之外的整数类型的prvalue(整数转换等级(4.13)小于int的等级)可以转换为int类型的prvalue ; 否则,源prvalue可以转换为unsigned int类型的prvalue。

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

因此,你所拥有的是第一个unsigned char的位向左移位,但仍然在now-greater int ,然后是第二个unsigned char的位。

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

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

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

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

unsigned char上没有任何操作(除了类型转换)。 在任何操作之前,会发生整数提升,将unsigned char转换为int 所以操作是向左移动一个int ,而不是一个unsigned char

C11 6.5.7按位移位算子

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

E1 << 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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM