这篇文章将基于 this one 构建但会更通用一些。
我经常看到指向大型结构的指针被转换为指向较小结构的指针,我认为这是可行的,因为指针只是结构中第一个字节的地址。我仍然有一个问题是,当大多数方法没有指向它们期望的类型时,如何处理指针。
我将使用 Socket API 作为示例:
sockaddr_storage
大于 sockaddr
,但指向 sockaddr_storage
的指针在传递之前会转换为指向 sockaddr
的指针类似于
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
因此,当指针指向比预期更大的结构时,函数往往会处理事情。他们说吗
“哦,传递给我的大小 (socklen_t addrlen
) 比我想象的要大。最好将此指针转换回 sockaddr_storage
!”
然后像这样访问其成员?或者他们做了更复杂的事情?
最佳答案
sockaddr
是 C 的穷人多态性习惯用法的完美示例。在面向对象语言中,sockaddr
将是一个基类,其中有多种协议(protocol)地址类型(sockaddr_in
、sockaddr_in6
、sockaddr_ll
等)是“派生的”。
基本上,sockaddr
被定义为具有一个类型 (sa_family
),该类型指定它真正保存的内容,后跟一些数据。指向 sockaddr
的指针通常指向派生结构 (sockaddr_*
),它指定数据的特定解释。
sockaddr_storage
与普通 sockaddr
类似,因为它不保存特定的协议(protocol)地址,仅保存存储空间。不同之处在于 sockaddr_storage
指定的空间比 sockaddr
更多,使其成为存储特定于协议(protocol)的 sockaddr
的合适类型。
查看普通 sockaddr
的函数首先查看 sa_family
,例如AF_INET
(对于 IPv4)或 AF_INET6
(对于 IPv6)或其他内容,然后将其赋予的指针强制转换为适当的 sockaddr
子类型(例如 IPv4 的 sockaddr_in
)。然后它可能会检查addrlen
以确保转换的指针指向足够的空间来容纳子类型。
关于将指向较大结构的指针转换为指向较小结构的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16026775/