首页 文章

动态分配内存时,“指针类型”有什么意义?

提问于
浏览
1

为什么我们有指针类型?例如

int *ptr;

我知道它的类型安全性,例如解除引用'ptr',编译器需要知道它解除引用ptr以输入int,而不是char或long等,但正如其他人所述Why to specify a pointer type?,这也是因为"we should know how many bytes to read. Dereferencing a char pointer would imply taking one byte from memory while for int it could be 4 bytes."这是有道理的 .

但是,如果我有这样的事情怎么办:

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));

4 回答

  • 3

    你在这里问两个不同的问题 - 为什么有不同的指针类型,为什么隐藏在typedef后面的指针?

    不同指针类型的主要原因来自指针算法 - 如果 p 指向 T 类型的对象,则表达式 p + 1 指向该类型的下一个对象 . 如果 p 指向4字节 int ,则 p + 1 指向下一个 int . 如果 p 指向一个128字节 struct ,则 p + 1 指向下一个128字节 struct ,依此类推 . 指针是具有附加类型语义的内存地址的抽象 .

    至于隐藏typedef背后的指针......

    如果类型的用户仍然必须知道类型的“指针”(即,如果你必须取消引用它,或者如果你),我们中的许多人(包括我自己)都会考虑将typedef后面的指针隐藏为坏样式永远将 malloc/calloc/realloc 的结果分配给它,等等 . 如果你试图抽象掉某些东西的“指针”,你需要的不仅仅是声明 - 你需要提供一个完整的API来隐藏所有的指针操作 .

    至于你的上一个问题,C中的最佳做法是不投出 malloc 的结果 . C中的最佳做法是完全不使用 malloc .

  • 0

    我认为这更像是类型定义样式的问题,而不是动态内存分配的问题 .

    老派C练习是通过标签来描述结构 . 你说

    struct foo {
        ...
    };
    

    然后

    struct foo foovar;
    

    要么

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

    但是很多人不喜欢不断输入关键字 struct . (我想我当时不能错; C总是喜欢简洁,有时似乎只是为了减少打字 . )所以使用 typedef 的形式变得非常流行(它受影响,或者受C影响):

    typedef struct {
        ...
    } Foo;
    

    然后

    Foo foovar;
    

    要么

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

    但是,由于原因不太明确,将指针引入typedef变得流行,如下所示:

    typedef struct {
        ...
    } Foo, *Foop;
    
    
    Foop foopointer = malloc(sizeof(*Foop));
    

    但这完全取决于风格和个人偏好,为人们想象的是清晰,方便或有用 . (但当然关于清晰度和便利性的观点,比如关于风格的观点,可以合法地改变 . )我已经看到指针typedef被贬低为误导或微观实践,但我不确定我现在可以对它们造成错误 .

    您还询问了演员表,我们也可以将 sizeof 调用的各种选项作为 malloc 的参数进行剖析 .

    你说是不是真的很重要

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

    要么

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

    第一个可能更清楚,因为你不必回去检查 FoopFoo * 是一回事 . 但是他们自1990年以来一直被弃用了,或者我认为如果你通常使用 new 而不是 malloc . )

    但那你应该把什么放进 sizeof() ?哪个更好,

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

    要么

    Foop foopointer = malloc(sizeof(Foo));
    

    同样,第一个可以更容易阅读,因为您不必返回并检查 FoopFoo * 是相同的事情 . 但出于同样的原因,还有第三种形式可以更清晰:

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

    现在你知道了,无论 foopointer 指向什么类型,你're allocating the right amount of space for it. This idiom works best, though, if it'最大限度地清楚 foopiinter 实际上是指向某种类型的指针,这意味着变体

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

    甚至

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

    可以认为更清晰 - 这可能是人们认为指针typedef不太完全有用的原因之一 .


    最重要的是,如果你找到有用的 PIP_ADAPTER_INFO ,不要使用它 - 使用 IP_ADAPTER_INFO (以及在需要时使用显式的 * )代替 . 有人认为 PIP_ADAPTER_INFO 可能有用,这就是为什么它太引人注目了 .

  • 1

    动态分配内存时,“指针类型”有什么意义?

    至少在你展示的例子中没有 .

    所以后续问题是,如果有一些指针是有意义的.1711452

    答案是:是的 .

    如果一个人需要opaque data type,那肯定是有意义的 .

    一个很好的例子是pthread_t type which defines a handle to a POSIX thread .

    根据实现,它被定义为

    • typedef struct bla pthread_t;

    • typedef struct foo * pthread_t;

    • typedef long pthread_t;

    并且由此抽象出实现的类型,因为它对用户没有兴趣,这可能不是你在问题中显示的意图.1717458_ .

  • 1

    为什么我们有指针类型?

    适应各种类型的大小和编码可能不同的体系结构 . C端口很好地适用于许多平台,甚至是新的平台 .


    今天,函数指针的大小与指向对象的指针大小不同 . 对象指针转换为 void * ,但函数指针可能不会 .

    指向 char 的指针的大小不必与指向 intunionstruct 的指针相同 . 这在今天并不常见 . 规范细节如下(我的重点):

    指向void的指针应具有与指向字符类型的指针相同的表示和对齐要求 . 同样,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求 . 所有指向结构类型的指针都应具有相同的表示和对齐要求 . 所有指向union类型的指针都应具有相同的表示和对齐要求 . 指向其他类型的指针不需要具有相同的表示或对齐要求 . C11dr§6.2.528

相关问题