簡體   English   中英

在C中無效指向結構指針

[英]Void pointers to struct pointers in C

我正在學習C,主要是由K&R學習,但現在我已經找到了面向對象的C pdf教程並且很着迷。 我正在經歷它,但我的C技能/知識可能無法完成任務。 這是教程: http//www.planetpdf.com/codecuts/pdfs/ooc.pdf

我的問題來自於在pdf的前幾章中查看許多不同的功能。 下面是其中之一。 (pdf的第14頁)

void delete(void * self){
     const struct Class ** cp = self;

     if (self&&*cp&&(*cp)->dtor)
                self = (*cp)->dtor(self);
     free(self);

 }

dtor是一個析構函數指針。 但是對於我的問題,對此的了解並不是必需的。

  • 我的第一個問題是,為什么** cp不變? 它是必要的還是只是徹底的,所以代碼編寫者不會做任何意外損壞的事情?
  • 其次,為什么cp指向指針(雙星號?)。 struct類在pdf的第12頁上定義。 我不明白為什么它不能成為單個指針,因為我們正在將自指針轉換為類指針。
  • 第三,如何將void指針更改為Class指針(或指向類指針的指針)? 我認為這個問題大多表明我對C的理解不足。我想象中的是一個空指針占用一定量的內存,但它必須小於Class指針,因為一個Class有很多“東西”在里面。 我知道一個void指針可以“強制轉換”到另一種類型的指針,但我不明白如何,因為可能沒有足夠的內存來執行此操作。

提前致謝

有趣的pdf。

我的第一個問題是,為什么** cp不變? 它是必要的還是只是徹底的,所以代碼編寫者不會做任何意外損壞的事情?

這是必要的,因此作者不會意外地做任何事情,是的,並且將指針的性質及其用途傳達給代碼的讀者

其次,為什么cp指向指針(雙星號?)。 struct類在pdf的第12頁上定義。 我不明白為什么它不能成為單個指針,因為我們正在將自指針轉換為類指針。

看一下創建指針pnew() (第13頁)的定義new()作為self傳遞給delete()的相同指針):

void * new (const void * _class, ...)
{
    const struct Class * class = _class;
    void * p = calloc(1, class —> size);
    * (const struct Class **) p = class;

因此,'p'被分配空間,然后取消引用並分配一個指針值(類中的地址;這就像解除引用並分配給一個int指針,但是我們分配一個地址而不是int。)。 這意味着p中的第一個東西是指向其類定義的指針。 但是,p被分配的空間不僅僅是那個(它還將保存對象的實例數據)。 現在再考慮delete()

 const struct Class ** cp = self;
 if (self&&*cp&&(*cp)->dtor)

當cp被解除引用時,由於它是指向指針的指針,它現在是一個指針。 指針包含什么? 一個地址。 什么地址? 指向由p指向的塊開頭的類定義的指針

這有點聰明,因為p實際上並不是指向指針的指針 - 它分配了更大的內存塊,其中包含特定的對象數據。 但是,在該塊的最開始是一個地址(類定義的地址),因此如果p被解引用到指針(通過強制轉換或cp),則可以訪問該定義。 因此,類定義僅存在於一個位置,但該類的每個實例都包含對該定義的引用。 合理? 如果將p類型化為這樣的結構將更清楚:

struct object {
  struct class *class;
    [...]
};

然后你可以使用類似p->class->dtor()而不是delete()中的現有代碼。 然而,這會弄亂並使更大的圖片復雜化。

第三,如何將void指針更改為Class指針(或指向類指針的指針)? 我認為這個問題大多表明我對C的理解不足。我想象中的是一個空指針占用一定量的內存,但它必須小於Class指針,因為一個Class有很多“東西”在里面。

指針就像一個int - 它有一個小的設置大小來保存一個值。 該值是內存地址。 當您取消引用指針(通過*-> )時,您正在訪問的是該地址處的內存。 但由於內存地址長度相同(例如,64位系統上的8個字節),無論類型如何,指針本身都具有相同的大小。 這就是對象指針'p'的神奇之處。 重新迭代:內存塊p指向的第一件事是一個地址,它允許它作為指針的指針,當取消引用時,你得到包含類定義的內存塊,與p的實例數據分開。

  1. 在這種情況下,這只是一個預防措施。 該函數不應該修改類(事實上,可能沒有任何東西),所以強制轉換為const struct Class *可以確保該類更難以無意中更改。

  2. 我不太熟悉這里使用的面向對象的C庫,但我懷疑這是一個討厭的伎倆。 self的第一個指針可能是對類的引用,因此解除引用self會給出一個指向該類的指針。 實際上, self總是可以被視為struct Class **

    圖表可能有助於:

      +--------+ self -> | *class | -> [Class] | .... | | .... | +--------+ 
  3. 請記住,所有指針都只是地址。*指針的類型與指針的大小無關; 它們都是32或64位寬,具體取決於您的系統,因此您可以隨時從一種類型轉換為另一種類型。 如果您嘗試在沒有強制轉換的情況下在指針類型之間進行轉換,編譯器會發出警告,但是void *指針總是可以轉換為沒有強制轉換的任何東西,因為它們在整個C中用於表示“通用”指針。

*:有一些奇怪的平台,這是不正確的,不同類型的指針實際上有時不同的大小。 但是,如果你正在使用其中一個,你就會知道它。 很可能,你不是。

  1. 如果代碼嘗試更改指向的對象中的任何內容,則const用於導致編譯錯誤。 當程序員只想讀取對象並且不打算更改它時,這是一個安全功能。

  2. **是因為它必須是傳遞給函數的內容。 將它重新聲明為不是它的東西將是一個嚴重的編程錯誤。

  3. 指針只是一個地址。 在幾乎所有現代CPU上,所有地址都是相同的大小(32位或64位)。 將指針從一種類型更改為另一種類型實際上不會更改該值。 它說要將該地址的內容視為不同的數據布局。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM