2013-09-29 69 views
3

我不明白這是什麼線做:鑄造的指針的整型常量

((struct Example*) 0x10000) 

我寫了一個測試程序:

#include <stdio.h> 

struct Elf{ 
    int bla; 
    char bla2; 
}; 

int main(){ 
    struct Elf *elfPtr; 
    printf("Before casting: %p\n", elfPtr); 

    elfPtr = ((struct Elf *)0x10000); 
    printf("After casting: %p\n", elfPtr); 

    return 0; 
} 

輸出是:

投射前:0xb776dff4

投射後:0x10000

這條線只做這個嗎?

elfPtr = 0x10000 
+0

在投射之前它正在打印一個垃圾地址,另外使用'%p'正確投射是'void *'.so'printf(「投射後:%p \ n」,elfPtr);'應該寫成' printf(「鑄造後:%p \ n」,(void *)elfPtr);'正確。 –

+0

由於'elfPtr'沒有被初始化,第一個'printf()'調用未定義的行爲。 – alk

+0

@alk你確定檢查未初始化的指針是未定義的行爲嗎?我認爲價值是未定義的,但不是行爲(即它將具有價值,並且該價值不會改變)。 – pburka

回答

5

這確實將指針設置爲特定的常量值,這在具有虛擬內存管理的系統中是一個壞主意。

一個值得注意的例外是帶內存映射資源的嵌入式系統。在這樣的系統中,硬件設計人員通常會預留一定範圍的內存地址以供替代使用,從而使程序員可以訪問硬件寄存器,就好像它們是常規內存空間的一部分一樣。

下面是一個例子*

struct UART { 
    char data; 
    char status; 
}; 
const UART *uart1 = 0xC0000; 
const UART *uart2 = 0xC0020; 

有了這個設置到位,嵌入式程序可以訪問UART的寄存器,如果他們struct的成員:

while (uart1->status & 0x02) { 
    uart1->data = 0x00; 
} 


* UART代表 Universal Asynchronous Receiver/Transmitter,一種通常用於異步點對點通信的硬件ication。

+1

好的答案,用'%p'打印,我們應該把地址轉換爲'void *'否則它是未定義的行爲,是否正確? –

+1

@GrijeshChauhan更正,'%p'需要'void *',否則就是UB。 – dasblinkenlight

+1

@GrijeshChauhan:對於char *'不需要投射。 – alk

2

通常,給一個指針指定一個任意值是一個壞主意。這就是編譯器不鼓勵它的原因,並且你需要添加轉換來讓編譯器確信你知道你在做什麼。 (你的代碼將把地址爲0x10000的內存當作struct Elf實例,至少在你的簡單例子中,它不是,它甚至可能不是可讀和/或可寫的內存,所以你會得到一個當您嘗試訪問它時崩潰。)

+2

向指針分配數字很有用的一種情況包括操作系統內核和設備驅動程序,您需要使用特定地址與設備進行通信。當所有數據都可用時(可能在預先存在的結構或API中),將指針變量中的數字「隱藏」也並不少見。 – pburka

+0

我希望如果任何數據被分配到該內存或對該內存的任何訪問都會導致分段錯誤......我是否正確? – Tonmoy

+0

@Tonmoy:如果內存不可訪問,那麼會出現段錯誤。但是,如果它*是*可訪問的(說是因爲它是其他一些數據結構的一部分)並且你寫了它,那麼你將覆蓋之前沒有任何直接症狀的東西。 – RichieHindle

0

使用該命令,您正在告訴編譯器,地址0x10000處的數據是類型爲「Elf」的結構的實例,並將該類型的指針指定給該地址。

請注意,您尚未在該地址實例化該類型的任何結構,或者甚至爲其保留內存,因此在嘗試引用其成員時,至少會得到垃圾,如果不是分段錯誤。

你真的應該避免使用絕對地址(除非例如低級別的微控制器編程),否則它會導致不可移植的代碼,即使它運行。

1

那行elfPtr = ((struct Elf *)0x10000);將使類型的指針* 精靈*點由十六進制數0x10000的標識的存儲器地址(十進制65536)

所以,無論有在那個內存地址,你就假設它是類型「精靈」