概要:
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 *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]
C語言指標強制型別轉換
一 舉例說明 上圖對應函式呼叫為int printf const char fmt,fmt為char 指標型別,所以共佔了32位位元組,但是 fmt執行的是乙個位元組,fmt 執行的是下乙個位元組,fmt得到乙個32位位址,char fmt得到是乙個執行位元組的指標,char fmt 4後正好執行了...
C語言指標強制型別轉換
概要 c語言中,任何乙個變數都必須占有乙個位址,而這個位址空間內的0 1 就是這個變數的值。不同的資料型別占有的空間大小不一,但是他們都必須有個位址,而這個位址就是硬體訪問的依據,而名字只是提供給程式設計師的一種記住這個位址的方便一點的方法。但是,不同的變數在機器中都是0 1 所以,我們不能簡單的通...
C語言指標強制型別轉換
一 舉例說明 上圖對應函式呼叫為int printf const char fmt,fmt為char 指標型別,所以共佔了32位位元組,但是 fmt執行的是乙個位元組,fmt 執行的是下乙個位元組,fmt得到乙個32位位址,char fmt得到是乙個執行位元組的指標,char fmt 4後正好執行了...