2017-04-14 84 views
1

我正在編寫一個程序,我必須修改目標進程內存/讀取它。C - 爲什麼在進行指針算術時轉換爲uintptr_t vs char *

到目前爲止,我使用void *的存儲地址還有投那些爲char *如果我需要改變(增加抵消或一般修改)

我聽說類型的stdint.h定義,但我沒有看到使用它作爲char *轉換的指針算法的區別(這看起來對我來說更適合C89)

所以我的問題:這兩種方法應該用於指針算術?在任何情況下,我是否應該考慮在char *上使用uintptr_t?

編輯1

基本上,我只需要知道,如果這會產生

0x00F00BAA hard coded memory adress in target 
process 
void* x = (void*)0x00F00BAA; 
char* y = (void*)0x00F00BAA; 
x = (uintptr_t)x + 0x123; 
y = (char*)y + 0x123; 

x == y? 
x == (void*)0x00F00CCD? 
y == (void*)0x00F00CCD? 
+0

我認爲這個標準並不能保證對一個'uintptr_t'變量進行算術修改後跟一個強制轉換爲'char *'會得到與將數學直接應用到'char *'相同的結果'uintptr_t'源自於,儘管我認爲如果這不成立,它會變得瘋狂。 – PSkocik

+0

@PSkocik當然不支持,它根本就不瘋狂。 –

+0

@AnttiHaapala如果我將uintptr_t移動3,我也希望相應的char *移動3.我不明白爲什麼平面內存模型平臺會想要做一些不同的事情。 – PSkocik

回答

2

在評論用戶R.,指出,以下是可能的,如果不正確的代碼打交道的地址在當前流程中無效。我已要求OP進行澄清。

如果您關心代碼的可移植性,請不要將指針算術使用uintptr_tuintptr_t是一個整數類型。對它的任何算術運算都是整數運算,而不是指針運算。

如果你有一個void*值,並且你想給它添加一個字節偏移量,那麼鑄造到char*是正確的方法。

很可能uintptr_t值的算術運算方式與char*算術運算方式相同,但絕對不能保證。 C標準提供的唯一保證是您可以將void*值轉換爲uintptr_t並再次返回,並且結果將與原始指針值進行比較。

而標準並不保證uintptr_t存在。如果沒有足夠寬的整數類型來保存轉換的指針值而不丟失信息,則實現不會定義uintptr_t

我實際上在系統(Cray矢量機器)上工作,其中uintptr_t算術不一定會工作。硬件有64位字,機器地址包含一個字的地址。類Unix操作系統需要支持8位字節,因此字節指針(void*,char*)包含一個字地址,其中存儲在64位字的其他未使用的高3位中的3位偏移量。指針/整數轉換隻是複製表示。結果是,將1加到char*指針會導致它指向下一個字節(偏移量用軟件處理),但轉換爲uintptr_t並加1將導致它指向下一個

底線:如果您需要指針算術,請使用指針算術。這就是它的目的。 (順便說一句,gcc有一個允許在void*上進行指針運算的擴展名,不要在便攜代碼中使用它,它也會導致一些奇怪的副作用,如sizeof (void) == 1。)

+0

我假設在這樣的架構上從'void *'轉換爲'char *'會轉換指針表示。但是,轉換回來會發生什麼?將未對齊的'char *'轉換回'void *'陷阱? – TrentP

+0

這個答案可能適用於另一個問題,但對於OP的問題完全錯誤。 OP正在考慮對這些指針使用指針類型和指針算法來存儲和操作「目標進程」(某種調試/內存窺探/戳動,我假設)中的地址。使用這個指針是無效的。指針只能指向程序本身的地址空間中的現有對象,而不是某個其他進程,並且它們的算術只有在它指向的對象內時纔是有效的。 –

+0

還要注意,儘管'uintptr_t'可以工作(並且不受未定義問題的影響,void *將受其影響),但它也假定調試器和目標進程使用相同的ISA/ABI,通常這是一個窮人在設計這種類型的軟件時作出的假設。相反,你應該使用一個整數類型來匹配目標進程中的(目標實現定義的)指針表示。例如,在ELF系統上,類似於'Elf32_Addr' /'Elf64_Addr'這樣的類型將是合適的。 –

相關問題