轉(zhuǎn)載:http://blog.csdn.net/mhjcumt/article/details/7355127
//數(shù)據(jù)類型轉(zhuǎn)換分為:數(shù)值類型轉(zhuǎn)換 ?, 指針類型轉(zhuǎn)化(重新解釋內(nèi)存)辉浦;
概要:
C語言中炫隶,任何一個(gè)變量都必須占有一個(gè)地址,而這個(gè)地址空間內(nèi)的0-1代碼就是這個(gè)變量的值珊搀。不同的數(shù)據(jù)類型占有的空間大小不一脉顿,但是他們都必須有個(gè)地址糕档,而這個(gè)地址就是硬件訪問的依據(jù),而名字只是提供給程序員的一種記住這個(gè)地址的方便一點(diǎn)的方法痊硕。但是赊级,不同的變量在機(jī)器中都是0-1代碼,所以寿桨,我們不能簡單的通過檢查一個(gè)值的位來判斷它的類型此衅。
例如强戴,定義如下:
int a;
float b;
double c;
long double d;
(假設(shè)它們所占的字節(jié)分別是4、8挡鞍、8骑歹、10,而且連續(xù)存儲(chǔ)于某個(gè)地址空間墨微,起始地址是100道媚,則我們可以得到如下內(nèi)存分布)
a變量就是由以地址100開始到103結(jié)束的4個(gè)字節(jié)內(nèi)存空間內(nèi)的0-1代碼組成。b變量則是由以地址104開始到112結(jié)束的8個(gè)字節(jié)內(nèi)存空間內(nèi)的0-1代碼組成翘县。而在機(jī)器中最域,這些內(nèi)存都是連續(xù)的0-1代碼,機(jī)器并不知道100~103是整型而104~111是float型锈麸,所有這些類型都是編譯器告知的镀脂。當(dāng)我們用a時(shí),由于前面把a(bǔ)定義為int型忘伞,則編譯器知道從a的地址開始向后取4個(gè)字節(jié)再把它解釋成int型薄翅。那么(float)a,就是先按照int類型取出該數(shù)值氓奈,再將該數(shù)值按照int to float的規(guī)則轉(zhuǎn)換成float型翘魄。所以強(qiáng)制類型轉(zhuǎn)換就是按照某個(gè)變量的類型取出該變量的值,再按照***to***的規(guī)則進(jìn)行強(qiáng)制轉(zhuǎn)轉(zhuǎn)換舀奶。如果是(類型名)常數(shù)暑竟,則是將該常數(shù)按照常數(shù)to類型 的規(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型或者其他類型蒜焊。同樣,我們也可以將任何一個(gè)常數(shù)轉(zhuǎn)換成int型再賦值給指針科贬。所有的指針?biāo)嫉目臻g大小都是4字節(jié)泳梆,他們只是聲明的類型不同鳖悠,他們的值都是地址指向某個(gè)東西,他們對(duì)于機(jī)器來說沒有本質(zhì)差別优妙,他們之間可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換乘综。
指針 to 指針的強(qiáng)制類型轉(zhuǎn)換是指將指針?biāo)傅膬?nèi)容的類型由原先的類型轉(zhuǎn)換為后面的類型。
int a = 1;
int *p = &a;
float *p1 = (float*)p;
則p和p1的值都是&a套硼,但是*p是將&a地址中的值按照int型變量進(jìn)行解釋卡辰,而*p1則是將&a地址中的值按照float型變量進(jìn)行解釋。
鑒于指針之間這種靈活的強(qiáng)制類型轉(zhuǎn)換的需求和出于簡化代碼的考慮邪意,ANSI C引入了空指針即void*九妈。void指針又名萬能指針,在現(xiàn)在的很多程序中雾鬼,當(dāng)參數(shù)不確定時(shí)就用萬能指針代替萌朱,這一類的指針在線程\進(jìn)程函數(shù)里特別常見。
ANSI C規(guī)定策菜,void指針可以復(fù)制給其他任意類型的指針嚷兔,其他任意類型的指針也可以復(fù)制給void指針,他們之間復(fù)制不需要強(qiáng)制類型轉(zhuǎn)換做入。當(dāng)然任何地址也可以復(fù)制給void型指針冒晰。我們在《網(wǎng)絡(luò)編程》中經(jīng)常會(huì)看到accept(socket, (struct sockaddr *)&saddr_c, &lenth)之類的語句在&saddr_c之前需要增加代碼(struct sockaddr *)是因?yàn)楫?dāng)此函數(shù)被設(shè)計(jì)的時(shí)候ANSI C還沒有提出void*的概念。所有的地址統(tǒng)一用struct sockaddr類型標(biāo)識(shí)竟块,該函數(shù)的第二個(gè)參數(shù)也是指向struct sockaddr類型的指針壶运,此處是強(qiáng)制類型轉(zhuǎn)換。
當(dāng)然浪秘,在某些編譯器中不同類型的指針也可以進(jìn)行直接賦值蒋情,但一般情況下會(huì)給出類型不匹配的警告。要求程序員顯示的給出指針強(qiáng)制類型轉(zhuǎn)換可以提醒程序員小心使用指針耸携,對(duì)于明確程序目的具有一定的好處棵癣。
1、指針類型強(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的類型如果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é)的解釋务甥,所以結(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]