[英]bitwise shifts, unsigned chars
任何人都可以詳細解釋這完成了什么? 我試圖學習c並且很難繞過它。
void tonet_short(uint8_t *p, unsigned short s) {
p[0] = (s >> 8) & 0xff;
p[1] = s & 0xff;
}
void tonet_long(uint8_t *p, unsigned long l)
{
p[0] = (l >> 24) & 0xff;
p[1] = (l >> 16) & 0xff;
p[2] = (l >> 8) & 0xff;
p[3] = l & 0xff;
}
詳細地說,這里是:
作為直接的答案; 它們都從左到右將變量的字節存儲在一個字節數組中。 tonet_short
為unsigned short
變量執行此操作,該變量由2個字節組成; tonet_long
用於unsigned long
變量,由4個字節組成。
我將為tonet_long
解釋它,而tonet_short
將只是你希望能夠自己得出它的變體:
unsigned
變量,當它們的位被逐位移位時,使它們的位向確定的一側移位以確定比特量,並使空出的位為0
,零。 即:
unsigned char asd = 10; //which is 0000 1010 in basis 2
asd <<= 2; //shifts the bits of asd 2 times towards left
asd; //it is now 0010 1000 which is 40 in basis 10
請記住,這是一個unsigned
變量,而這些可能是不正確的signed
的變量。
按位和&
操作者在兩側的兩個操作數的位進行比較,返回1
(真),如果兩者都是1
(真),和0
(假)如果它們中的任何一個或兩者都是0
(假); 它為每一位做到這一點。 例:
unsigned char asd = 10; //0000 1010
unsigned char qwe = 6; //0000 0110
asd & qwe; //0000 0010 <-- this is what it evaluates to, which is 2
現在我們知道了按位移位和按位 - 並且,讓我們到達函數tonet_long
的第一行:
p[0] = (l >> 24) & 0xff;
這里,由於l
是unsigned long
,則(l >> 24)
將被評估為第一4 * 8 - 24 = 8
的可變的比特l
,這是第一個字節的l
。 我可以像這樣想象這個過程:
abcd efgh ijkl mnop qrst uvwx yz.. .... //letters and dots stand for
//unknown zeros and ones
//shift this 24 times towards right
0000 0000 0000 0000 0000 0000 abcd efgh
注意我們不改變l
,這只是l >> 24
的評估,這是暫時的。
然后,以十六進制(基數16)為0000 0000 0000 0000 0000 0000 1111 1111
的0xff
以逐位移位的l
進行逐位求和。 它是這樣的:
0000 0000 0000 0000 0000 0000 abcd efgh
&
0000 0000 0000 0000 0000 0000 1111 1111
=
0000 0000 0000 0000 0000 0000 abcd efgh
因為a & 1
將完全依賴於a
,所以它將是a
; 其余的一樣......看起來這是一個多余的操作,而且確實如此。 然而,對其他人來說,這一點很重要。 這是因為,例如,當您評估l >> 16
,它看起來像這樣:
0000 0000 0000 0000 abcd efgh ijkl mnop
由於我們只需要ijkl mnop
部分,我們必須丟棄abcd efgh
,這將在0000 0000
的幫助下完成, 0xff
在其相應的位上。
我希望這會有所幫助,剩下的就像它到目前為止一樣,所以......是的。
這些例程將16位和32位值從本機字節順序轉換為標准網絡(大端)字節順序。 它們通過從原生值移位和屏蔽8位塊並將它們按順序存儲到字節數組中來工作。
如果我看到它正確,我基本上切換短和長的字節順序...(反轉數字的字節順序)並將結果存儲在希望有足夠空間的地址:)
explain verbosely
- 好的......
void tonet_short(uint8_t *p, unsigned short s) {
short
通常是16位值(最大值:0xFFFF)
uint8_t
是無符號的8位值, p
是指向某些無符號8位值的指針(來自我們假設至少2個連續值的代碼)。
p[0] = (s >> 8) & 0xff;
這將取s
值的“上半部分”並將其放在數組p
的第一個元素中。 所以我們假設s==0x1234
。
首先將s
移位8位( s >> 8 == 0x0012
)
那么它與0xFF
AND運算,結果存儲在p[0]
。 ( p[0] == 0x12
)
p[1] = s & 0xff;
現在請注意,當我們執行該移位時,我們從未更改s
的原始值,因此s
仍然具有0x1234
的原始值,因此當我們執行第二行時,我們只是執行另一個逐位AND並且p[1]
得到s
的值的“下半部分”( p[0] == 0x34
)
這同樣適用於你在那里的其他功能,但它是一個long
而不是短,所以我們假設在這種情況下p
有足夠的空間用於所有32位(4x8),我們也必須做一些額外的移位。
此代碼用於將16位或32位數字序列化為字節( uint8_t
)。 例如,將它們寫入磁盤,或通過網絡連接發送它們。
16位值分為兩部分。 一個包含最高有效(高)8位,另一個包含最低有效(低)8位。 首先存儲最重要的字節,然后存儲最不重要的字節。 這稱為大端或“網絡”字節順序。 這就是函數名為tonet_
的原因。
對於32位值的四個字節也是如此。
& 0xff
操作實際上是無用的。 當16位或32位值轉換為8位值時,低8位( 0xff
)被隱式屏蔽。
位移用於將所需字節移動到最低8位。 考慮32位值的位:
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
最重要的字節是名為A
的8位。 為了將它們移動到最低的8位,該值必須右移24。
功能的名稱是一個很大的提示......“凈短”和“凈長”。
如果你考慮十進制...說我們有兩張紙如此之小我們只能在每一張紙上寫一個數字,因此我們可以用它們來記錄從0到99:00,01,02的所有數字。 .. 08,09,10,11 ...... 18,19,20 ...... 98,99。基本上,一張紙上有“十位”欄(假設我們的十進制數為10),其他的“單位”。
內存的工作方式類似於每個字節可以存儲0..255的數字,所以我們在256的基數上工作。如果你有兩個字節,其中一個將是“二百五十六”列,另一個是“單位”列。 要計算出組合值,您將前者加倍256並添加后者。
在紙面上,我們在左邊用更重要的數字寫數字,但是在計算機上不清楚更重要的值是應該在更高還是更低的內存地址中,因此不同的CPU制造商選擇了不同的約定。
因此,一些計算機存儲258 - 其為1 * 256 + 2 - 低= 1高= 2,而其他計算機存儲低= 2高= 1。
這些函數的作用是將內存從CPU正常使用的內容重新排列為可預測的順序 - 即,更重要的值進入較低的內存地址,最終將“單位”值放入最高的內存地址。 這是存儲適用於所有計算機類型的數字的一致方式,因此當您想通過網絡傳輸數據時,它非常棒; 如果接收計算機對base-256數字使用不同的內存排序,它可以將它們從網絡字節順序移動到它喜歡的任何順序,然后將它們解釋為CPU本機數字。
因此,“to net short”將最重要的8位s
打包到p[0]
- 較低的內存地址。 它實際上並不需要& 0xff
因為在取16個輸入位並將它們8移到“右”之后,所有左手8位都保證為0,這是來自& 0xFF
的影響 - 例如:
1010 1111 1011 0111 // = decimal 10*256^3 + 15*256^2 + 11*256 + 7
>>8 0000 0000 1010 1111 // move right 8, with left-hand values becoming 0
0xff 0000 0000 1111 1111 // we're going to and the above with this
& 0000 0000 1010 1111 // the bits that were on in both the above 2 values
// (the and never changes the value)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.