2013-10-20 78 views
1

假設我有一個int值指針,其值爲0x5。我想爲該值添加一個0x3的偏移量。如果我想對指針進行常規算術(不是指針算術),我應該使用uintptr_t嗎?

我應該做這樣的(方法A):

int* pointer = 0x5; 
int offset = 0x3; 

pointer = pointer + (offset/sizeof(int)); // pointer is now equal to 0x8 

或類似這樣的(方法B):

uintptr_t pointer = 0x5; 
pointer = pointer + 0x3; 

int* ptr = (int*) pointer; // pointer is now equal to 0x8 

我問這個看到這個問題後:What is uintptr_t data type

我被告知不要使用常規整數並假裝它們是指針。

+1

您也可以強制轉換爲char *'並添加3:它會得到相同的結果。 – dasblinkenlight

+0

通常,你不應該對指針進行常規算術。你能解釋你實際想要達到的目標嗎? (另外,你的第一個例子是不正確的。) – pburka

+0

@pburka:我正在寫一個低級的DLL,它將被注入一個目標進程來修改它的內存。偏移量是從基地址計算某些值的地址。 – user2899050

回答

1
int *pointer = 0x5; 
int offset = 0x3; 
pointer = pointer + (offset/sizeof(int)); 

假設sizeof(int) == 4,除法將評估爲0和指針將不會更改。如果你有代替通過sizeof(int)分,指針會被3*sizeof(int)char單位提前。

uintptr_t pointer = 0x5; 
pointer = pointer + 0x3; 
int *ptr = (int *) pointer; 

但這其實設置ptr相同的值ptr = (int *)0x8會有。 (這是壓倒性的可能,這不是一個有效的指針到任何東西。)

以上都不是正常辦法做這樣的事情C.慣用的方法是轉換爲char *和回:

int *pointer = 0x5; 
ptrdiff_t offset = 0x3; 
pointer = (int *) (((char *)pointer) + offset); 
assert (pointer == (int *)0x8); 
+1

是否有我們避免'uintptr_t'的原因?爲什麼這是一種正常的方式來轉換爲char *'? – user2899050

+0

它主要是歷史性的 - 這個習語早在'uintptr_t'發明之前就已經開發出來了。然而,即使在今天,如果完全符合C11的實現(注意:我不知道是否有任何完全符合C11的實現),uintptr_t是可選的,並且有實際的實現會發現它很困難提供(例如,某些微控制器具有16位int和24位指針)。但是,如果'uintptr_t'在特定的實現中可用,我相信標準確實需要我的第三個片段來完成同樣的事情,如果'char *'被'uintptr_t'替代。 – zwol

+0

據我記得,不能保證'uintptr_t'上的算術與指針上的算術具有相同的效果。只能保證你可以用'void *'值來回轉換'uintptr_t'值。一些體系結構(例如分段存儲器模型)可能實現與整數算術完全不同的指針算術。 – pburka

1

一般而言,在投射到char *unsigned char *,並在這裏做你的算術 - 因爲sizeof(char)==1定義,你會真正做「常規」算術,與你沒有留下「指針域」中受益任何方式,你都沒有違反鋸齒規則。

2

您不能以便攜方式對uintptr_t執行算術運算。下面是該類型是如何定義的:

7.18.1.4能夠保持對象指針

以下類型表示具有任何有效的指針的孔隙可以被轉換爲的性質的帶符號的整數類型整數類型這種類型的,再轉換回指向void,結果將比較等於原始指針:

intptr_t

以下類型表示一個無符號整數型與任何有效的指針的孔隙可以被轉換爲這種類型的屬性,然後轉換回指向void,結果將比較等於原始指針:

uintptr_t

這些類型是可選的。

請注意,該規範沒有說明如何表示指針。在大多數實現中,uintptr_t值上的算術可能會有預期的結果,但是如果您希望代碼是可移植的,則應該使用指針算術,因爲它具有明確指定的語義。

一個平臺的例子,其中uintptr_t算術可能有意想不到的行爲是IBM的z/OS。在傳統的31位模式下(是,31),最重要的指針位是爲系統保留的。如果你有兩個指針ab,它們只有該位不同,那麼將這些指針與a==b進行比較將如預期的那樣返回1(真),並且用a-b將返回值減去它們。但是,如果將這些指針轉換爲uintptr_t值並將它們進行比較,==將返回0,並且-將返回非0。