簡體   English   中英

指針訪問和數組訪問之間的值差異

[英]Difference in values between pointer access and array access

有人可以澄清我的錯誤解釋嗎? 我知道由於代碼的輸出結果,我的理解是不正確的(請參閱問題的底部)。 提前致謝。

為了澄清,以下各行的每個段是什么意思?:

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

它與以下行有何不同:

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

我對以上內容的解釋是:

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

我的解釋有什么錯誤? 我認為我對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

對於閱讀材料的任何提示或參考,我將不勝感激。 謝謝。

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

頂行將指針轉換為取消引用前的無符號8位值,而秒數則將指針轉換為取消引用前的無符號32位值。 最上面一行取消引用一個字節,最下面一行取消引用整個4個字節。

要解決您的其他問題:

我的解釋有什么錯誤? 我認為我對segment2領域缺乏了解...轉換(u32 *)和(u8 *)有什么區別?

對於地址的頂行和底行,地址長度為32位的解釋都是正確的。

我可以挑剔,說:“您沒有給我們提供足夠的信息”。 從技術上講,這是正確的,但只需要作一些假設即可。 u8u32不是標准C類型,您可以將它們定義為任何類型,但是大概它們代表無符號的8位值(例如uchar )和無符號的32位值(例如unsigned )。 假設是這樣,讓我們​​看一下您所理解的內容,並說明剩下的內容。

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

現在, BufferAddress是一個BufferAddress至少在32位系統上,通常用於指針。 由於它們始終是總線的大小,因此在64位系統上,指針是64位。

因此,Method1正在打印數組的元素和數組的地址。 很好,很酷。

方法2:

*(u8 *)(BufferAddress + i),BufferAddress + i

BufferAddress是一個無符號整數,您正在向其添加值以獲取其他地址。 這是數組的基本要點-內存將是連續的,並且您可以通過提高每個元素的字節數來訪問下一個元素。 因為它是一個u8數組,所以您只需前進1。但是,這很重要-如果它是一個int數組,則您需要BufferAddress +(i * 4),而不是BufferAddress + i,因為每個int的大小為4字節。 順便說一下,這就是指針算術在C中的工作方式。如果執行了&&((((u32 *)BufferAddress)+ 1),您將得到0x100004而不是0x100001,因為您將BufferAddress強制轉換為4byte指針,並且編譯器知道當您查看下一個元素時,它必須相距4個字節。

因此(BufferAddress+i)是u8數組的第i個元素的地址。 (u8 *)將BufferAddress從無聊的整數強制轉換為指向u8類型的內存位置的指針,因此,當您執行*(u8 *) ,編譯器知道將其視為u8。 您可以這樣做(u64 *) ,編譯器會說“哦!此內存區域為64位”,並嘗試以這種方式解釋值。

這可能使方法3中的情況變得清晰起來。 您將獲得每個數組元素的適當地址,但您要告訴編譯器“將該內存區域作為32位數據進行處理”。 因此,每次使用*(u32 *)時,您都在讀取數組的4個字節並將其視為無符號int。 順便說一句,一旦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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM