2011-12-23 94 views
2

這兩行代碼有什麼區別?C指針語法

int *ptr = &x; 

void* q = &x; 
int* p = q; 

我很新的C和指針的概念 - 已主要講授Java的 - 所以只是有點困惑。

在此先感謝。

回答

3

void *用於標註C中的通用指針。
含義它可以指向任何類型。

因此,在第一種情況下,您使用指向int的指針,以便任何使用它的人都知道它正在操作整數。

在第二種情況void* q = &x;中,通過gereric指針指向一個整數地址。
問題是,它不清楚這個指針指向什麼類型。

因此,第一個和兩個例子具有相同的效果(在您的具體示例中),但void *是不安全的這樣使用。

+1

感謝您的回答。如果有的話,'*'的位置有什麼不同? – bobble14988 2011-12-23 10:23:10

+4

'int * ptr'和'int * ptr'之間沒有區別,它只是編寫約定 – Zoneur 2011-12-23 10:33:49

2

ptrp的影響在兩種情況下都是相同的,因爲void *指針保證在轉換之間可以轉換。

void *q = &x只是將x的地址存儲在q中,而不關心x指向的內容。然後int *p = q將該地址分配給其語義描述爲其指向int的實體。

注意,在這種情況下,操作是安全的,因爲xint型和pint *類型。如果您將q分配給類型的指針,例如double *,則不會如此。

1

兩個陳述都是一樣的,但第一個是首選,因爲第二個是你擺脫危險的類型。

類型的主要目的是阻止你分配不兼容的變量,如蘋果和汽車。

因此,

void* q = &x;

擺脫X

int* p = q; 

的類型,而這一次蒙上未知類型的整數指針。你最好把q表示爲(int *)來表示你意識到了危險。

3

void * q =&x;

這可能是值得理解的東西如何表示在內存中,所以你明白了void*的含義。指針是內存中包含另一個位置的位置。對於真實世界的例子,請考慮以下代碼:

int x = 4; 
int* y = &x; 
void* z = &x; 

在我的64位系統上,我可以使用gdb來檢查內存。結果如下表所示:

Address   | Memory Value        | C expression 
================================================================================ 
0x7fffffffdf8c | 0x04 0x00 0x00 0x00      | int x = 4; 
0x7fffffffdf98 | 0x8c 0xdf 0xff 0xff 0xff 0x7f 0x00 0x00 | int* y = &x; 
0x7fffffffdf90 | 0x8c 0xdf 0xff 0xff 0xff 0x7f 0x00 0x00 | void* z = &x; 

我們在這裏看到什麼?那麼,0x7fffffffdf8c0x7fffffffdf90被值0x04佔用,並且我平臺上的所有零 - 整數都是4字節寬,順序是小端,因此這些字節與人們期望讀取的內容相反。然後,我們看到接下來的8個字節被x的地址佔用,同樣也是第二個指針。

所以使用指針的過程是在地址處讀取地址並使用它。這聽起來像你可能對這個概念很滿意,所以,繼續前進:

指針的類型不會影響指針的大小。這是關鍵。看看上面的兩個指針值,它們實際上都是相同的大小。這裏的大小值談到目標內存 - 它指示編譯器加載和操作一定量(字節數 - 一種類型的大小/寬度)的內存。

void*,正如其他人所說的,是「無類型的」。相反,僅僅是一個指針而且編譯器/ C語言將不能支持你對它進行解引用,因爲沒有類型信息 - 沒有辦法安全地告訴你要讀的目標地址有多少內存。

但是,這個事實有時是有用的。使用類型的想法是在代碼中提供一致性 - 如果函數需要64位整數,則使用類型會強制執行此要求,以免引入錯誤。然而,有時候,你不介意你得到的是什麼類型。在這些情況下,你的要求是「一些記憶,任何記憶!」 - 這個我能想到的最好的例子是memcpy的 - 這可能工作有點像這樣:

void *memcpy(void * s1, const void* s2, size_t n) 
{ 
    char *r1 = s1; 
    const char *r2 = s2; 
    while (n) { 
     *r1++ = *r2++; 
     -n; 
    } 
    return s1; 
} 

Adapted from uclibc。在這裏,變量類型根本不重要 - 在內部,函數決定在sizeof(char)類型中操縱內存(char通常但不總是一個字節寬),但它同樣可以在uint64_t或其他一些值上操作。這裏所有的類型都是控制從起始地址開始考慮多少個字節作爲類型的一部分。

給你另一個表,這裏的一些類型大小的比較:

Address of ptr | Type in code | Memory it "sees" when dereferenced 
=========================================================================== 
0x7fffffffdf90 | unsigned 64-bit | 0x8c 0xdf 0xff 0xff 0xff 0x7f 0x00 0x00 
0x7fffffffdf90 | unsigned 32-bit | 0x8c 0xdf 0xff 0xff 
0x7fffffffdf90 | unsigned 16-bit | 0x8c 0xdf 
0x7fffffffdf90 | unsigned 8-bit | 0x8c 
0x7fffffffdf90 | void*   | Doesn't know how wide it is. 

你可能會問,爲什麼有在libc函數沒有強制轉換 - 好了,沒有必要。所有的指針都是相同的大小,所以不需要做任何事情。