为什么我们有指针类型?例如
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 回答
你在这里问两个不同的问题 - 为什么有不同的指针类型,为什么隐藏在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
.我认为这更像是类型定义样式的问题,而不是动态内存分配的问题 .
老派C练习是通过标签来描述结构 . 你说
然后
要么
但是很多人不喜欢不断输入关键字
struct
. (我想我当时不能错; C总是喜欢简洁,有时似乎只是为了减少打字 . )所以使用typedef
的形式变得非常流行(它受影响,或者受C影响):然后
要么
但是,由于原因不太明确,将指针引入typedef变得流行,如下所示:
但这完全取决于风格和个人偏好,为人们想象的是清晰,方便或有用 . (但当然关于清晰度和便利性的观点,比如关于风格的观点,可以合法地改变 . )我已经看到指针typedef被贬低为误导或微观实践,但我不确定我现在可以对它们造成错误 .
您还询问了演员表,我们也可以将
sizeof
调用的各种选项作为malloc
的参数进行剖析 .你说是不是真的很重要
要么
第一个可能更清楚,因为你不必回去检查
Foop
和Foo *
是一回事 . 但是他们自1990年以来一直被弃用了,或者我认为如果你通常使用new
而不是malloc
. )但那你应该把什么放进
sizeof()
?哪个更好,要么
同样,第一个可以更容易阅读,因为您不必返回并检查
Foop
和Foo *
是相同的事情 . 但出于同样的原因,还有第三种形式可以更清晰:现在你知道了,无论
foopointer
指向什么类型,你're allocating the right amount of space for it. This idiom works best, though, if it'最大限度地清楚foopiinter
实际上是指向某种类型的指针,这意味着变体甚至
可以认为更清晰 - 这可能是人们认为指针typedef不太完全有用的原因之一 .
最重要的是,如果你找到有用的
PIP_ADAPTER_INFO
,不要使用它 - 使用IP_ADAPTER_INFO
(以及在需要时使用显式的*
)代替 . 有人认为PIP_ADAPTER_INFO
可能有用,这就是为什么它太引人注目了 .至少在你展示的例子中没有 .
所以后续问题是,如果有一些指针是有意义的.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_ .
适应各种类型的大小和编码可能不同的体系结构 . C端口很好地适用于许多平台,甚至是新的平台 .
今天,函数指针的大小与指向对象的指针大小不同 . 对象指针转换为
void *
,但函数指针可能不会 .指向
char
的指针的大小不必与指向int
或union
或struct
的指针相同 . 这在今天并不常见 . 规范细节如下(我的重点):