簡體   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