1、鋪墊
在分析上面的語句前,我們先從簡單的入手。先來區別和理解下面這兩個定義。
float *g(); 和 float (*h) ();
直接上答案:由於( )結合的優先級別高於*,所以g先和後面的( )結合,構成乙個函式,該函式的返回值是乙個指向float 數的指標。同理,h是乙個函式指標,它所指向的函式的返回值是乙個浮點數。
當我們知道如何宣告乙個給定型別的變數,那麼不難得出該型別的型別轉換:只需要把宣告中的變數名和宣告末尾的分號去掉,然後將剩下的部分用乙個括號整個「封裝」起來。最簡單的例子比方說我們以前學過的強制轉換 (int) value這類的,但是我們現在稍微複雜一些。如下:
float (*h) (); 表示h是乙個指向返回值為浮點型別的函式的指標,所以有
(float (*) () ) 表示乙個「指向返回值為浮點型別的函式的指標」的型別轉換
2、理解
有了上面的鋪墊之後,我們就開始理解(*(void (*)())0)();這個語句。
1) (void (*)()) 裡面的這個和鋪墊的一樣,是乙個型別轉換,表示乙個「指向返回值為void型別的函式的指標」的型別轉換。
2) (void (*)()) 0 這是表示將常數0轉換為「指向返回值為void的函式指標」型別。
3) 有了1) 和 2)的理解之後,我們就明白,0是乙個函式指標,它指向的函式的返回值型別為void,這樣就比較好辦了,那我們就按照使用指標變數的方法去理解它。我們使用乙個指標變數的時候,前面會帶乙個*號,同理,對於這樣乙個函式指標,我們在呼叫它的時候。也類似地這麼呼叫,就是(*(void (*)())0)();這就分析完了。
3、補充
這個例子主要運用在計算機位址方面,比方說arm晶元一上電的時候,是從0位址處開始執行程式。而要對各個狀態字進行配置或者存入某個記憶體塊的時候,處理的方法也都是把乙個常數(也就是這個位址)轉換成乙個指標型別,然後對這個指標進行操作就能對該位址進行操作,這方面在嵌入式的配置方面見得比較多。
我之所以說這個例子對我有幫助是這樣的,如下:。
pos == iofpga_do_data_addr(iofpga_if_get_dod_addr(), pfifo) ;
#define iofpga_do_data_addr(base, reg)((unsigned int)&(((struct st_iofpga_do_data *)((int)base))->reg))
右邊的表示式我一看就知道在幹嘛了(因為在此之前我看過標題的例子),我們看一下右邊的表示式對這base和reg這兩個形參做了什麼事情,很明顯嘛:
1)首先把base強制轉換為int型別,注意,它是乙個常數。
2)結合上面的例子分析,(struct st_iofpga_do_data *)((int)base) 和上面的例子用法一樣,就是把乙個常數轉換成乙個指標,這 裡是轉換成自定義的結構體指標。
3)((struct st_iofpga_do_data *)((int)base))->reg) 把這個常數轉換成結構體指標之後,在這個結構體中找到傳入的reg成員。
4) &(((struct st_iofpga_do_data *)((int)base))->reg)) 找到該結構體裡面的這個成員之後,用&取其位址
5) (unsigned int)&(((struct st_iofpga_do_data *)((int)base))->reg) &取到這個成員的位址之後,強制轉換為(unsigned int)型別
6)分析完畢....
函式指標的強制型別轉換
先給出結論 函式指標是可以通過強制型別轉換而指向具有不同函式簽名的函式的,但是,轉換後,該函式指標沒辦法正確呼叫所指向的函式 不能給函式傳遞引數。下文給出得出這個結論的小故事。前幾天的任務要求寫乙個logger類,該類對外提供一些靜態的方法,但不生成物件。該類的主要作用是用來輸出訊息,不同的是可以由...
指標型別轉換
當我們初始化乙個指標或給乙個指標賦值時,賦值號的左邊是乙個指標,賦 值號的右邊是乙個指標表示式。在我們前面所舉的例子中,絕大多數情況下,指 針的型別和指標表示式的型別是一樣的,指標所指向的型別和指標表示式所指向 的型別是一樣的。例十四 1。float f 12.3 2。float fptr f 3。...
指標型別轉換
指標型別轉換 當我們初始化乙個指標或給乙個指標賦值時,賦值號的左邊是乙個指標,賦值號的右邊是乙個指標表示式。在我們前面所舉的例子中,絕大多數情況下,指標的型別和指標表示式的型別是一樣的,指標所指向的型別和指標表示式所指向的型別是一樣的。例十四 1 float f 12.3 2 float fptr ...