[英]Difference in values between pointer access and array access
有人可以澄清我的錯誤解釋嗎? 我知道由於代碼的輸出結果,我的理解是不正確的(請參閱問題的底部)。 提前致謝。
為了澄清,以下各行的每個段是什么意思?:
*(u8 *)((u32)BufferAddress + (u32)i)
它與以下行有何不同:
*(u32 *)((u32)BufferAddress + (u32)i)
我對以上內容的解釋是:
我的解釋有什么錯誤? 我認為我對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位的解釋都是正確的。
我可以挑剔,說:“您沒有給我們提供足夠的信息”。 從技術上講,這是正確的,但只需要作一些假設即可。 u8
和u32
不是標准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.