2013-06-26 56 views
2

有人能澄清我的錯誤解釋嗎?我知道我的理解是不正確的,因爲我的代碼的結果輸出(請參閱問題的底部)。 在此先感謝。指針訪問和數組訪問之間的值差異

爲了澄清,什麼是以下行的每個段的意思是?:

*(u8 *)((u32)BufferAddress + (u32)i) 

它是如何從以下線路不同:

*(u32 *)((u32)BufferAddress + (u32)i) 

我上面的解釋是:

  1. segment1 =((u32)BufferAddress +(u32)i)=>確定一個地址爲一個整數。
  2. segment2 =(u32 *)(segment1)=>將指針處理爲待處理地址,其中指針的長度爲32位。
  3. segment3 = *(segment2)=>取消引用指針以獲取駐留在計算出的地址的值。

我的解釋是什麼不正確?我認爲我的缺乏理解在第二部分領域...鑄造(u32 *)和(u8 *)有什麼區別?

這裏是讓我意識到我有知識差距代碼:

初始化代碼:

main(...) { 
    ... 
    u8 *Buffer = malloc(256); 
    ... 
    Buffer[0] = 1; 
    Buffer[1] = 0; 
    Buffer[2] = 0; 
    Buffer[3] = 4; 
    Buffer[4] = 0; 
    Buffer[5] = 0; 
    qFunction(... , Buffer, 6, ...); 
    ... 
} 

qFunction(... , const u8 *BufferPointer, u32 BufferLength, ...) { 
    u32 BufferAddress; 
    ... 
    BufferAddress = (u32) BufferPointer; 
    ... 

    /* Method 1: */ 
    for (i=0; i < BufferLength; i++) 
      printf("%d, %p\n", BufferPointer[i], &BufferPointer[i]); 

    /* Method 2: */ 
    for (i=0; i < BufferLength; i++) 
      printf("%d, 0x%lx\n", *(u8 *)(BufferAddress+i), BufferAddress+i); 

    /* Method 3: */ 
    for (i=0; i < BufferLength; i++) 
      printf("%d, 0x%lx\n", *(u32 *)(BufferAddress+i), BufferAddress+i); 
    ... 
} 

方法1和方法2的輸出如我所料(兩者都相同):

1, 0x1000000 
0, 0x1000001 
0, 0x1000002 
4, 0x1000003 
0, 0x1000004 
0, 0x1000005 

但是,方法3的輸出對我來說似乎很奇怪;只有部分結果與方法1/2相同:

-1442840511, 0x1000000 
11141120, 0x1000001 
43520, 0x1000002 
4, 0x1000003 
0, 0x1000004 
0, 0x1000005 

我很感激任何提示或參考資料。 謝謝。

+1

macduff的回答是正確的,但是一個評論加上;你應該儘量避免將指針轉換爲整數,因爲這是不必要的,如果將來決定構建64位(指針將是64位而不是32位),會導致問題。 –

回答

3

我可以挑剔,並說「你沒有給我們足夠的信息」。從技術上講,這是事實,但只需要做出一些假設。u8u32不是標準的C類型,你可以讓它們對任何東西都進行typedefed,但可能它們表示一個無符號的8位值(例如uchar)和一個無符號的32位值(例如unsigned)。假設,讓我們看看你理解的那些,並解釋第三個離開的地方。

BufferPointer是一個常量u8 *,這意味着它是一個類型爲u8的常量指針。這意味着它指向的數組是8位無符號類型。

現在,BufferAddress是一個u32 - 這是指針的典型代表,至少在32位系統上。由於它們始終是總線的大小,在64位系統上,指針是64位。

因此,方法1打印數組的元素和數組的地址。這很好,很酷。

方法2:

*(U8 *)(BufferAddress + I),BufferAddress +我

BufferAddress是一個無符號整數,您要添加值,它得到了其他地址。這是數組的一個基本點 - 內存將是連續的,您可以通過推進每個元素的字節數來訪問下一個元素。因爲它是一個u8數組,所以你只需提前1.這裏有一個問題 - 如果它是一個整數數組,那麼你需要BufferAddress +(i * 4),而不是BufferAddress + i,因爲每個int的大小是4字節。順便說一下,這就是指針運算在C中的工作方式。如果你執行了'(&(((u32 *)BufferAddress)+ 1),你會得到0x100004而不是0x100001,因爲你將BufferAddress轉換爲4字節的指針,編譯器知道當你在看下一個元素時,它必須是4個字節。因此(BufferAddress+i)是u8數組的第i個元素的地址。 (u8 *)將BufferAddress從一個無聊的整數轉換爲指向u8類型的內存位置的指針,以便當您執行*(u8 *)時,編譯器知道將它視爲u8。你可以做(u64 *),編譯器會說「哦!這個內存區域是64位」,並試圖以這種方式解釋這些值。

這可能會說明方法3中發生了什麼。你得到每個數組元素的適當地址,但是你要告訴編譯器「將這個區域的內存視爲32位數據」。因此,每次使用*(u32 *)時,您都會讀取數組的4個字節,並將其視爲無符號整數。順便說一句,一旦i> = 3,你正在碰到未定義的行爲,因爲你正在讀取數組之外。

讓我嘗試給什麼你在這方面的記憶看起來像一個可視化:

0x1000000 = 1 
0x1000001 = 0 
0x1000002 = 0 
0x1000003 = 4 
0x1000004 = 0 
0x1000005 = 0 

對於方法2,i = 2時,你看BufferAddress(= 0x1000000)+ 3,即0x1000002,其中編號爲0。編譯器知道它只有一個字節,所以隨之而來。

但是對於method3,當i = 3時,您告訴編譯器將其視爲32位。所以它看不到'0',它看到0,4,0,0,並且使用這些數字來得出一個整數值,這肯定不會是4.

3
*(u8 *)((u32)BufferAddress + (u32)i) 
*(u32 *)((u32)BufferAddress + (u32)i) 

上方的行注塑指針到一個無符號的8比特值之前解除引用,而秒它轉換爲無符號的32位值解引用之前。最上面一行取消了一個字節,最下面一行取消了整個4個字節。

爲了解決您的其他問題:

什麼是不正確我的解釋呢?我認爲我對 的理解缺失在segment2區域...鑄造(u32 *)和(u8 *)之間有什麼區別 ?

地址長度爲32位的解釋對於頂部和底部的代碼行都是正確的。