2015-11-23 68 views
4

我目前正在從「shellcoder的手冊」中學習,我對c很有深刻的理解,但是最近我遇到了一些我無法理解的代碼。a [0] = addr&0xff是什麼?

下面是一段代碼:

  char a[4]; 
      unsigned int addr = 0x0806d3b0; 
      a[0] = addr & 0xff; 
      a[1] = (addr & 0xff00) >> 8; 
      a[2] = (addr & 0xff0000) >> 16; 
      a[3] = (addr) >> 24; 

所以,問題是什麼呢這是什麼地址& 0xFF的(和三線下方),是什麼讓>> 8到它(我知道它把它分成8次2)? Ps:不要猶豫,告訴我,如果你有我應該使用的標籤的想法。

+1

'(addr)>> X'不是被8分割的。這在某些情況下可能是正確的,但'>>'是'addr'的*右移*由'X'給出的*字節數。 –

回答

6

變量addr是32位數據,而數組a中的每個元素是8位。代碼的作用是將addr的32位複製到數組a中,一次一個字節。

讓我們走這條線:

a[1] = (addr & 0xff00) >> 8; 

,然後做一步一步來。

  1. addr & 0xff00這得到的位8到值的15 addr,操作後的結果是0x0000d300
  2. >> 8這會將位移到右側,因此0x0000d300將變爲0x000000d3
  3. 分配掩碼的結果值並切換到a[1]
+0

實際上是否需要掩飾?隱式轉換爲「char」不會處理這個問題嗎? (順便說一句,我也建議一個明確的'unsigned char a [4]'。) – usr2564301

+0

@Jongware是的,這樣做隱含地工作。是的,使用'unsigned char'(或'uint8_t'更具體)將是一個好主意。 –

+1

在實踐中,如果你假設'char'是8位寬的,你可以不用屏蔽。 (C標準說它至少需要8位寬。)掩碼使得代碼可以移植到char大於8位的平臺上。是的,'unsigned char'更好。 –

1

顯然,該代碼從addr隔離單個字節以將它們存儲在陣列a所以它們可以被索引英寸第一行

a[0] = addr & 0xff; 

掩模出最低值的字節通過使用0xff作爲位掩碼;後面的幾行也是一樣的,但是也會將結果轉移到最右邊的位置。最後,最後一行

a[3] = (addr) >> 24; 

不再需要屏蔽,因爲所有不必要的信息都被輪班丟棄了。

2
unsigned char a[4]; /* I think using unsigned char is better in this case */ 
unsigned int addr = 0x0806d3b0; 
a[0] = addr & 0xff; /* get the least significant byte 0xb0 */ 
a[1] = (addr & 0xff00) >> 8; /* get the second least significant byte 0xd3 */ 
a[2] = (addr & 0xff0000) >> 16; /* get the second most significant byte 0x06 */ 
a[3] = (addr) >> 24; /* get the most significant byte 0x08 */ 
1

該代碼實際上是將一個32位地址存儲在4個字符長的數組中。你可能知道,char有一個字節(8位)。它首先複製地址的第一個字節,然後移位,複製第二個字節,然後移位等等。

3

的代碼試圖執行所述數據輸入端序。具體來說,它試圖對數據實施小端行爲。下面是交代:

a[0] = addr & 0xff; /* gets the LSB 0xb0 */ 
a[1] = (addr & 0xff00) >> 8; /* gets the 2nd LSB 0xd3 */ 
a[2] = (addr & 0xff0000) >> 16; /* gets 2nd MSB 0x06 */ 
a[3] = (addr) >> 24; /* gets the MSB 0x08 */ 

因此,基本上,代碼被掩蔽和分離出的數據的每個字節並且將其存儲在數組中的「a」中的小端格式。

1

也是,爲什麼不形象化的比特移位結果..

char a[4]; 
    unsigned int addr = 0x0806d3b0; 
    a[0] = addr & 0xff; 
    a[1] = (addr & 0xff00) >> 8; 
    a[2] = (addr & 0xff0000) >> 16; 
    a[3] = (addr) >> 24; 

    int i = 0; 
    for(; i < 4; i++) 
    { 
     printf("a[%d] = %02x\t", i, (unsigned char)a[i]); 
    } 
    printf("\n"); 

輸出:

a[0] = b0 a[1] = d3 a[2] = 06 a[3] = 08 
1

我除了給出多個答案,代碼有一些缺陷需要被固定以使代碼便攜。特別是,由於其實現定義的簽名,因此char類型用於存儲值非常危險。非常經典的C錯誤。如果代碼是從一本書中提取的,那麼你應該閱讀這本書。

雖然我們在這,我們也可以整理代碼,使其過於明確,以避免潛在的未來維修的錯誤,刪除整數文字等

#include <stdint.h> 

uint8_t a[4]; 
uint32_t addr = 0x0806d3b0UL; 
a[0] = addr & 0xFFu; 
a[1] = (addr >> 8) & 0xFFu; 
a[2] = (addr >> 16) & 0xFFu; 
a[3] = (addr >> 24) & 0xFFu; 

面具& 0xFFu是一些隱式類型促銷嚴格來說不需要,但是它們可以避免一些錯誤的整數類型的錯誤編譯器警告。或者,每個轉移結果可以投到uint8_t,那也可以。

+0

非常感謝您修復我的代碼,但也有一些我不明白的東西(我不喜歡不明白的東西),0xFFu掩碼是什麼,以及如何刪除舊的掩碼?我問,因爲你顯然非常擅長c編程,我真的很想了解更多關於c的知識,特別是這類東西。 – Th3Meg4ph0re

+1

@ Th3Meg4ph0re舊面具的類型爲'int',這沒有任何意義。不同之處在於他們在轉換之前對int進行了屏蔽。現在假設'addr'也是一個int類型,你可以在簽名類型上進行右移。如果在符號位的位置碰巧有任何位,你的代碼可能會破壞,因爲在C中負數的右移不能很好地定義在C中。你可以得到算術或邏輯移位,或者可能是某種東西其他。整數字面值後面的'u'或'U'後綴確保它是無符號類型。 – Lundin

+1

@ Th3Meg4ph0re對於在移位之前或之後的掩碼,只要兩個操作數都是無符號的,它並不重要。在像8和16位這樣的小型CPU上,屏蔽之後效率更高,因爲它可以用8位指令而不是32位指令來完成。更重要的是,之後的屏蔽使代碼看起來更整齊。你甚至可以把第一行寫成'a [0] =(addr >> 0)&0xFFu;'如果你希望它更整齊地排隊,它將產生等效的機器碼。 – Lundin

相關問題