概要:
C語(yǔ)言中,任何一個(gè)變量都必須占有一個(gè)地址,而這個(gè)地址空間內(nèi)的0-1代碼就是這個(gè)變量的值。不同的數(shù)據(jù)類(lèi)型占有的空間大小不一,但是他們都必須有個(gè)地址,而這個(gè)地址就是硬件訪問(wèn)的依據(jù),而名字只是提供給程序員的一種記住這個(gè)地址的方便一點(diǎn)的方法。但是,不同的變量在機(jī)器中都是0-1代碼,所以,我們不能簡(jiǎn)單的通過(guò)檢查一個(gè)值的位來(lái)判斷它的類(lèi)型。
例如,定義如下:
int a;
float b;
double c;
long double d;
(假設(shè)它們所占的字節(jié)分別是4、8、8、10,而且連續(xù)存儲(chǔ)于某個(gè)地址空間,起始地址是100,則我們可以得到如下內(nèi)存分布)
a變量就是由以地址100開(kāi)始到103結(jié)束的4個(gè)字節(jié)內(nèi)存空間內(nèi)的0-1代碼組成。b變量則是由以地址104開(kāi)始到112結(jié)束的8個(gè)字節(jié)內(nèi)存空間內(nèi)的0-1代碼組成。而在機(jī)器中,這些內(nèi)存都是連續(xù)的0-1代碼,機(jī)器并不知道100~103是整型而104~111是float型,所有這些類(lèi)型都是編譯器告知的。當(dāng)我們用a時(shí),由于前面把a(bǔ)定義為int型,則編譯器知道從a的地址開(kāi)始向后取4個(gè)字節(jié)再把它解釋成int型。那么(float)a,就是先按照int類(lèi)型取出該數(shù)值,再將該數(shù)值按照int to float的規(guī)則轉(zhuǎn)換成float型。所以強(qiáng)制類(lèi)型轉(zhuǎn)換就是按照某個(gè)變量的類(lèi)型取出該變量的值,再按照***to***的規(guī)則進(jìn)行強(qiáng)制轉(zhuǎn)轉(zhuǎn)換。如果是(類(lèi)型名)常數(shù),則是將該常數(shù)按照常數(shù)to類(lèi)型 的規(guī)則進(jìn)行強(qiáng)制轉(zhuǎn)換。
指針也是一個(gè)變量,它自己占據(jù)一個(gè)4個(gè)字節(jié)的地址空間(由于程序的尋址空間是2^32次方,即4GB,所以用4個(gè)字節(jié)表示指針就已經(jīng)能指向任何程序能夠?qū)ぶ返降目臻g了,所以指針的大小為4字節(jié)),他的值是另一個(gè)東西的地址,這個(gè)東西可以是普通變量,結(jié)構(gòu)體,還可以是個(gè)函數(shù)等等。由于,指針的大小是4字節(jié),所以,我們可以將指針強(qiáng)制轉(zhuǎn)換成int型或者其他類(lèi)型。同樣,我們也可以將任何一個(gè)常數(shù)轉(zhuǎn)換成int型再賦值給指針。所有的指針?biāo)嫉目臻g大小都是4字節(jié),他們只是聲明的類(lèi)型不同,他們的值都是地址指向某個(gè)東西,他們對(duì)于機(jī)器來(lái)說(shuō)沒(méi)有本質(zhì)差別,他們之間可以進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換。指針 to 指針的強(qiáng)制類(lèi)型轉(zhuǎn)換是指將指針?biāo)傅膬?nèi)容的類(lèi)型由原先的類(lèi)型轉(zhuǎn)換為后面的類(lèi)型。
int a = 1;
int *p = &a;
float *p1 = (float*)p;
則p和p1的值都是&a,但是*p是將&a地址中的值按照int型變量進(jìn)行解釋?zhuān)?p1則是將&a地址中的值按照f(shuō)loat型變量進(jìn)行解釋。
鑒于指針之間這種靈活的強(qiáng)制類(lèi)型轉(zhuǎn)換的需求和出于簡(jiǎn)化代碼的考慮,ANSI C引入了空指針即void*。void指針又名萬(wàn)能指針,在現(xiàn)在的很多程序中,當(dāng)參數(shù)不確定時(shí)就用萬(wàn)能指針代替,這一類(lèi)的指針在線程/進(jìn)程函數(shù)里特別常見(jiàn)。
ANSI C規(guī)定,void指針可以復(fù)制給其他任意類(lèi)型的指針,其他任意類(lèi)型的指針也可以復(fù)制給void指針,他們之間復(fù)制不需要強(qiáng)制類(lèi)型轉(zhuǎn)換。當(dāng)然任何地址也可以復(fù)制給void型指針。我們?cè)凇毒W(wǎng)絡(luò)編程》中經(jīng)常會(huì)看到accept(socket, (struct sockaddr *)&saddr_c, &lenth)之類(lèi)的語(yǔ)句在&saddr_c之前需要增加代碼(struct sockaddr *)是因?yàn)楫?dāng)此函數(shù)被設(shè)計(jì)的時(shí)候ANSI C還沒(méi)有提出void*的概念。所有的地址統(tǒng)一用struct sockaddr類(lèi)型標(biāo)識(shí),該函數(shù)的第二個(gè)參數(shù)也是指向struct sockaddr類(lèi)型的指針,此處是強(qiáng)制類(lèi)型轉(zhuǎn)換。
當(dāng)然,在某些編譯器中不同類(lèi)型的指針也可以進(jìn)行直接賦值,但一般情況下會(huì)給出類(lèi)型不匹配的警告。要求程序員顯示的給出指針強(qiáng)制類(lèi)型轉(zhuǎn)換可以提醒程序員小心使用指針,對(duì)于明確程序目的具有一定的好處。
1、指針類(lèi)型強(qiáng)制轉(zhuǎn)換:
int m;
int *pm = &m;
char *cp = (char *)&m;
pm指向一個(gè)整型,cp指向整型數(shù)的第一個(gè)字節(jié)
2、結(jié)構(gòu)體之間的強(qiáng)制轉(zhuǎn)換
struct str1 a;
struct str2 b;
a=(struct str1) b; //this is wrong
a=*((struct str1*)&b); //this is correct
3、關(guān)于一個(gè)程序的解釋
int main(void)
{
int a[4] = {1, 2, 3, 4};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)((int)a+1);
int *c = *(a + 1);
PRintf("%x, %x,%x/n", ptr1[-1], *ptr2,*c);
return 0;
}
輸出分別為4 和2000000,2式子&a+1表示的是指針加法運(yùn)算,而不是普通的數(shù)值加法運(yùn)算
vs2008下,其中a = 0x001bfc18(&a + 1) = 0x001bfc28而 a+1 = 0x001bfc1c
&a + 1 的值取決于a的類(lèi)型如果a申明int a;則&a + 1 = 0xFFFF5704 = a + 1如果 int a(ArryLen);則&a + 1 = 0xFFFF5700 + 4 * ArryLen <> a + 1
a 表示數(shù)組的起始地址,(int ) a 表示將a的地址轉(zhuǎn)化為一個(gè)整形數(shù),(int)a + 1 表示普通的數(shù)值加法運(yùn)算,(int *)((int)a + 1)表示把(int )a + 1轉(zhuǎn)化為整型指針的地址。該地址指向數(shù)組a(0)的第一個(gè)字節(jié)(從0計(jì)數(shù)),因?yàn)槭莍nt型的 所以需要四個(gè)字節(jié)的解釋?zhuān)越Y(jié)果是a(0)的后三個(gè)字節(jié)和a(1)的第一個(gè)字節(jié)組成的值,該值受大小端的影響。
*(a + 1) 此時(shí)的a已經(jīng)是一個(gè)常指針了,這個(gè)表達(dá)式計(jì)算出a所指向元素后面的第2個(gè)元素的地址,然后對(duì)它解引用得到相應(yīng)的值。這個(gè)表達(dá)式等價(jià)于
int last = a[1]
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注