C 語言中不同類型指針的大小是否完全相同,為什麼?


C99 spec

section 6.2.5

A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to quali?ed or unquali?ed versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

section 6.3.2.3

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer.

第一段就是說,void*和所有指向各種數據的指針都和char *一致,包括大小,對齊方式。第二段就是說,所有指向函數的指針都一致。

但是沒有哪一段說數據指針和函數指針一致!

當然,實際中你能遇到的系統差不多都是一致的。

另外在一些系統中指針本身還有一些類型,例如80286上引入的near和far指針,它們的尺寸是不同的,哪怕指向同一種類型。不過這些都不包括在C標準中,屬於實現的擴展。


同一平台上數據指針是一樣的,數據指針和函數指針不一定一樣。實際應用中基本不會遇到數據指針和函數指針大小不一的情況,遇上了就說明你太偏門了。遇到需要保存函數指針的定義一個

typedef int (*func_ptr_t)();

func_ptr_t foo = (func_ptr_t)bar;

可能比 uintptr_t 更具有可移植性。


古老的8086/80286平台下,指針分near和far兩種(學過8086彙編的應該可以比較容易理解),其大小不一樣,但跟類型無關,僅和指針本身的near/far有關。

在目前所需要考慮的主流平台如:x86、x64、IA64、arm等平台,基本不再需要考慮指針本身的大小差異了。另外現代的標準還規定編譯器應該定義如下類型:

std::intptr_t 和void*同大小的有符號整數

std::uintptr_t 和void*同大小的無符號整數

這兩個類型通常用於將指針類型轉換成整數類型用於運算、存儲或傳遞的場合。

另外,C++標準規定了用於表示數據大小的類型:std::size_t,以及表示指針差值的類型std::ptrdiff_t 這兩個類型通常用於需要將指針/大小進行數值運算的場合。

在目前的主流平台與編譯器中,它們恰好與void*同大小,但為了更好的可移植性,如果要將一個指針強制轉換成整數類型,應該用std::uintptr_t或std::intptr_t


相同,他們存的都是地址,只是在間接調用時的解讀方式不一樣


指針在實質上是一個內存地址,內存地址的長度跟CPU的定址有關。

在32位系統上, CPU用32位表示一個內存地址。這樣的系統上一個指針佔據4個位元組。

在64位系統上, CPU用64位表示一個內存地址。這樣的系統上一個指針佔據8個位元組。


同一個平台的sizeof操作符的結果是一樣的,但是進行+ -等運算時,步長是和指針的類型有關的。


相同,存的都是地址,類型是在找到地址後的解析不同(根據類型的size)。


原來最早的有far指針和near指針之別

現在應該沒啥差別了吧

可以自己sizeof()試試


同一平台下指針大小都相同,不同類型的指針步長不同;比如PC x86上是4位元組,x64上是8位元組, 不過這個結論不包括void*


平台相關性~sizeof實測才可靠


應該一樣,而且指針的size與平台相關。


指針其實是一個整數

計算機中的內存都是編址的,每個地址都有一個符號,就像家庭地址或者IP地址一樣。指針,是一個無符號整數(unsigned int,因不致歧義,下簡稱「整數」),它是一個以當前系統定址範圍為取值範圍的整數。聲明指針和聲明一個無符號整數實質上並無區別。

32位系統的定址能力(地址空間)是4GB二進位表示長度為32比特,也就是4B。同理,64位系統取值範圍為int類型長度為8B。

具體的解釋參考

http://zh.wikipedia.org/wiki/%E6%8C%87%E9%92%88_%28%E4%BF%A1%E6%81%AF%E5%AD%A6%29


指針大小與本機sizeof(unsigned long)一致,其表示範圍與unsigned long一致


推薦閱讀:

指針的指針定義為什麼用int ** ptr,而不是int *ptr?
C語言如何封裝printf函數?
C語言結構體內部的函數指針有什麼意義?
一條C語言語句不一定是原子操作,但是一個彙編指令是原子操作嗎?
c語言函數是如何獲取傳入的數組(指針)的指針所指向內容的長度的,有辦法嗎?

TAG:編程語言 | C編程語言 | 指針 |