天天看點

C語言指針強制類型轉換

C語言中,任何一個變量都必須占有一個位址,而這個位址空間内的0-1代碼就是這個變量的值。不同的資料類型占有的空間大小不一,但是他們都必須有個位址,而這個位址就是硬體通路的依據,而名字隻是提供給程式員的一種記住這個位址的友善一點的方法。但是,不同的變量在機器中都是0-1代碼,是以,我們不能簡單的通過檢查一個值的位來判斷它的類型。

例如,定義如下:

int a;

 float b;

double c;

 long double d;

(假設它們所占的位元組分别是4、8、8、10,而且連續存儲于某個位址空間,起始位址是100,則我們可以得到如下記憶體分布)

a變量就是由以位址100開始到103結束的4個位元組記憶體空間内的0-1代碼組成。b變量則是由以位址104開始到112結束的8個位元組記憶體空間内的0-1代碼組成。而在機器中,這些記憶體都是連續的0-1代碼,機器并不知道100~103是整型而104~111是float型,所有這些類型都是編譯器告知的。當我們用a時,由于前面把a定義為int型,則編譯器知道從a的位址開始向後取4個位元組再把它解釋成int型。那麼(float)a,就是先按照int類型取出該數值,再将該數值按照int to float的規則轉換成float型。是以強制類型轉換就是按照某個變量的類型取出該變量的值,再按照***to***的規則進行強制轉轉換。如果是(類型名)常數,則是将該常數按照常數to類型 的規則進行強制轉換。

指針也是一個變量,它自己占據一個4個位元組的位址空間(由于程式的尋址空間是2^32次方,即4GB,是以用4個位元組表示指針就已經能指向任何程式能夠尋址到的空間了,是以指針的大小為4位元組),他的值是另一個東西的位址,這個東西可以是普通變量,結構體,還可以是個函數等等。由于,指針的大小是4位元組,是以,我們可以将指針強制轉換成int型或者其他類型。同樣,我們也可以将任何一個常數轉換成int型再指派給指針。所有的指針所占的空間大小都是4位元組,他們隻是聲明的類型不同,他們的值都是位址指向某個東西,他們對于機器來說沒有本質差别,他們之間可以進行強制類型轉換。

指針 to 指針的強制類型轉換是指将指針所指的内容的類型由原先的類型轉換為後面的類型。

int a = 1;

int *p = &a;

float *p1 = (float*)p;

則p和p1的值都是&a,但是*p是将&a位址中的值按照int型變量進行解釋,而*p1則是将&a位址中的值按照float型變量進行解釋。

鑒于指針之間這種靈活的強制類型轉換的需求和出于簡化代碼的考慮,ANSI C引入了空指針即void*。void指針又名萬能指針,在現在的很多程式中,當參數不确定時就用萬能指針代替,這一類的指針線上程\程序函數裡特别常見。

ANSI C規定,void指針可以複制給其他任意類型的指針,其他任意類型的指針也可以複制給void指針,他們之間複制不需要強制類型轉換。當然任何位址也可以複制給void型指針。我們在《網絡程式設計》中經常會看到accept(socket, (struct sockaddr *)&saddr_c, &lenth)之類的語句在&saddr_c之前需要增加代碼(struct sockaddr *)是因為當此函數被設計的時候ANSI C還沒有提出void*的概念。所有的位址統一用struct sockaddr類型辨別,該函數的第二個參數也是指向struct sockaddr類型的指針,此處是強制類型轉換。

當然,在某些編譯器中不同類型的指針也可以進行直接指派,但一般情況下會給出類型不比對的警告。要求程式員顯示的給出指針強制類型轉換可以提醒程式員小心使用指針,對于明确程式目的具有一定的好處。

1、指針類型強制轉換:

int m;

int *pm = &m;

char *cp = (char *)&m;

pm指向一個整型,cp指向整型數的第一個位元組

2、結構體之間的強制轉換

struct str1 a;

struct str2 b;

a=(struct str1) b;                  //this is wrong

a=*((struct str1*)&b);         //this is correct

3、關于一個程式的解釋

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表示的是指針加法運算,而不是普通的數值加法運算

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 表示數組的起始位址,(int ) a 表示将a的位址轉化為一個×××數,(int)a + 1 表示普通的數值加法運算,(int *)((int)a + 1)表示把(int )a + 1轉化為整型指針的位址。該位址指向數組a(0)的第一個位元組(從0計數),因為是int型的 是以需要四個位元組的解釋,是以結果是a(0)的後三個位元組和a(1)的第一個位元組組成的值,該值受大小端的影響。

 *(a + 1)  此時的a已經是一個常指針了,這個表達式計算出a所指向元素後面的第2個元素的位址,然後對它解引用得到相應的值。這個表達式等價于

int last = a[1]

出處:http://blog.csdn.net/mhjcumt/article/details/7355127