簡體   English   中英

動態分配內存時“指針類型”有什么意義?

[英]What is the point of “pointer types” when you dynamically allocate memory?

為什么我們有指針類型? 例如

int *ptr;

我知道它的類型安全性,例如要解引用“ ptr”,編譯器需要知道其將ptr引用為int類型,而不是char或long類型,等等,但是這里概述的其他原因為何要指定指針類型? ,這還因為“我們應該知道要讀取多少個字節。取消引用char指針將意味着從內存中獲取一個字節,而對於int則可能是4個字節。” 那講得通。

但是,如果我有這樣的事情怎么辦:

typedef struct _IP_ADAPTER_INFO {
    struct _IP_ADAPTER_INFO* Next;
    DWORD ComboIndex;
    char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
    char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
    UINT AddressLength;
    BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
    DWORD Index;
    UINT Type;
    UINT DhcpEnabled;
    PIP_ADDR_STRING CurrentIpAddress;
    IP_ADDR_STRING IpAddressList;
    IP_ADDR_STRING GatewayList;
    IP_ADDR_STRING DhcpServer;
    BOOL HaveWins;
    IP_ADDR_STRING PrimaryWinsServer;
    IP_ADDR_STRING SecondaryWinsServer;
    time_t LeaseObtained;
    time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;

PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));

在這里聲明類型PIP_ADAPTER_INFO有什么意義? 畢竟,與前面的示例不同,我們已經分配了足夠的內存供指針指向(使用malloc),因此在此處定義類型是否多余? 我們將從內存中讀取盡可能多的已分配數據。

另外,請注意:以下4個聲明之間是否有區別,還是有最佳實踐?

PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));

要么

PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)malloc(sizeof(IP_ADAPTER_INFO));

要么

IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));

要么

IP_ADAPTER_INFO *pAdapterInfo = (PIP_ADAPTER_INFO)malloc(sizeof(IP_ADAPTER_INFO));

您在這里問兩個不同的問題-為什么具有不同的指針類型,為什么將指針隱藏在typedef后面?

指針類型不同的主要原因來自於指針算術-如果p指向類型T的對象,則表達式p + 1指向該類型的下一個對象。 如果p指向一個4字節的int ,則p + 1指向下一個int 如果p指向128字節的struct ,則p + 1指向下一個128字節的struct ,依此類推。 指針是具有附加類型語義的內存地址的抽象

至於將指針隱藏在typedef后面...

如果類型的用戶仍然必須知道類型的“指針性”(即,如果您必須取消引用它,或者如果您必須取消引用它),我們中的許多人(包括我自己)都認為將指針隱藏在typedef后面是不好的樣式。將malloc/calloc/realloc的結果分配給它,等等)。 如果您試圖抽象出某種東西的“指針性”,則需要做的不僅僅是聲明-您還需要提供一個完整的API,該API還隱藏所有指針操作。

至於您的最后一個問題,C語言中的最佳實踐是不轉換malloc的結果。 C ++的最佳實踐是根本不使用malloc

我認為這是類型定義樣式的問題,而不是動態內存分配的問題。

老式的C實踐是通過標記來描述結構。 你說

struct foo {
    ...
};

接着

struct foo foovar;

要么

struct foo *foopointer = malloc(sizeof(struct foo));

但是很多人不喜歡一直在輸入該關鍵字struct (我想我不會錯; C一直偏愛簡潔,有時似乎只是為了減少鍵入。)因此,使用typedef的形式變得非常流行(它影響了C ++,或受C ++影響):

typedef struct {
    ...
} Foo;

接着

Foo foovar;

要么

Foo *foopointer = malloc(sizeof(Foo));

但是隨后,由於不清楚的原因,將指針也扔到typedef中變得很普遍,如下所示:

typedef struct {
    ...
} Foo, *Foop;


Foop foopointer = malloc(sizeof(*Foop));

但這全都是風格和個人喜好的問題,以服務於人們認為清晰,方便或有用的事物。 (但是,當然,關於清晰度和便利性的意見,例如關於樣式的意見,可以合理地改變。)我已經看到指針typedef被貶低為一種誤導或Microsoftian的做法,但是我不確定現在是否可以對它們進行指責。

您還詢問了有關強制轉換的信息,我們還可以剖析sizeof調用的各種選項作為malloc的參數。

你說不重要

Foop foopointer = (Foop)malloc(sizeof(*Foop));

要么

Foop foopointer = (Foo *)malloc(sizeof(*Foop));

第一個可能更清晰一些,因為您不必回去檢查FoopFoo *是否相同。 但是他們在C語言方面都是很差的做法,並且至少在某些圈子里,自1990年代以來,它們已經過時了。 這些強制轉換在直接C語言中被認為是分散注意力和不必要的-盡管當然在C ++中它們是必需的,或者我想如果您使用的是C ++編譯器來編譯C代碼。 (當然,如果您編寫的是直接的C ++代碼,通常會使用new而不是malloc 。)

但是,您應該在sizeof()什么呢? 哪個更好,

Foop foopointer = malloc(sizeof(*Foop));

要么

Foop foopointer = malloc(sizeof(Foo));

同樣,第一個可以更容易閱讀,因為您不必回去檢查FoopFoo *是同一件事。 但是出於同樣的原因,還有第三種形式甚至可以更清楚:

Foop foopointer = malloc(sizeof(*foopointer));

現在您知道,無論foopointer指向什么類型,您都在foopointer分配適當的空間。 但是,如果最大程度地了解foopiinter實際上是指向某種類型的指針,則該慣用法最有效。

Foo *foopointer = malloc(sizeof(*foopointer));

甚至

struct foo *foopointer = malloc(sizeof(*foopointer));

仍然可以被認為更清晰-這可能是人們認為指針typedef不夠有用的原因之一。


最重要的是,如果您仍然與我在一起:如果您覺得PIP_ADAPTER_INFO有用,請不要使用它-使用IP_ADAPTER_INFO (以及在需要時使用顯式* )。 有人認為PIP_ADAPTER_INFO可能有用,這就是為什么它存在的原因,但是支持使用它的理由並不太吸引人。

動態分配內存時“指針類型”有什么意義?

至少對於您顯示的示例,沒有任何示例。

因此,后續問題將是在typedef情況下定義指針的類型是否有意義。

答案是:是的。

如果需要一種不透明的數據類型,這絕對是有道理的。

一個很好的例子是pthread_t類型,它定義POSIX線程的句柄

根據實現,它定義為

  • typedef struct bla pthread_t;
  • typedef struct foo * pthread_t;
  • typedef long pthread_t;

並由此抽象出了實現的類型,因為它對用戶不感興趣,這可能不是您在問題中顯示的struct的意圖。

為什么我們有指針類型?

適應各種類型的大小和編碼可能不同的體系結構。 C可以很好地移植到許多平台,甚至是新穎的平台。


如今,指向函數的指針與指向對象的指針具有不同的大小已經很普遍了。 對象指針隱藏到void * ,而函數指針可能沒有。

指向char的指針不必與指向intunionstruct的指針相同。 今天這並不常見。 規格詳細信息如下(我強調):

指向void的指針應具有與字符類型的指針相同的表示和對齊要求。 同樣,指向兼容類型的合格或不合格版本的指針應具有相同的表示形式和對齊要求。 所有指向結構類型的指針應具有相同的表示和對齊要求。 指向聯合類型的所有指針應具有相同的表示和對齊要求。 指向其他類型的指針不必具有相同的表示或對齊要求 C11dr§6.2.528

暫無
暫無

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

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