2

这篇文章将建立在这篇文章的基础上,会更通用一点。

我经常看到指向大型结构的指针被转换为指向较小结构的指针,我认为这是可行的,因为指针只是结构中第一个字节的地址。我还有一个问题是当大多数方法没有指向他们期望的类型时如何处理指针。

我将以 Socket API 为例:

sockaddr_storage大于sockaddrbut 指针在传递给函数之前被强制sockaddr_storage转换为指向的指针sockaddr

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

因此,当指针指向比预期更大的结构时,如何函数往往会处理事情。他们说

“哦,socklen_t addrlen传递给我的大小 () 比我想象的要大。最好将此指针转换回sockaddr_storage!”

然后像那样访问它的成员?还是他们做了更复杂的事情?

4

3 回答 3

3

sockaddr是 C 的穷人多态习语的一个完美例子。在 OO 语言中,sockaddr将是一个基类,从该基类中“派生”了许多协议地址类型(sockaddr_insockaddr_in6sockaddr_ll等)。

基本上,asockaddr被定义为具有一个类型 ( sa_family) 来指定它真正拥有的内容,然后是一些数据。指向 a 的指针sockaddr通常指向派生结构 ( sockaddr_*),它指定数据的特定解释。

sockaddr_storage类似于 plain sockaddr,因为它没有特定的协议地址,只有存储空间。不同之处在于它sockaddr_storage指定了比 更多的空间sockaddr,使其成为存储特定于协议的sockaddrs 的合适类型。

一个查看普通文本的函数sockaddr首先查看sa_family,例如AF_INET(对于 IPv4)或AF_INET6(对于 IPv6)或其他东西,然后将其给出的指针转换为适当的sockaddr子类型(例如sockaddr_in对于 IPv4)。然后它可能会检查addrlen以确保转换的指针指向足够的空间来保存子类型。

于 2013-04-16T00:36:23.997 回答
1

@nneonneo 对套接字示例中发生的事情给出了很好的答案。

但总的来说:

"What I still have a question about is how to most methods handle pointers when they aren't pointing at the type they expect."

重要的是他们接收到的结构的布局是否与函数计划用它做的事情相匹配。C 提供了一些布局保证,使之成为可能。在这些情况下,函数确实会获得指向它们期望的类型的指针。只是在内存中还有一些额外的东西可以忽略。

通常,被调用函数中没有downcast发生任何事情。它只是在base class较大结构的一部分上运行

于 2013-04-16T00:56:04.253 回答
0

我的猜测是函数根本不在乎,如果指向的结构比预期的大,阅读它至少不会造成访问冲突。较大结构的第一部分当然必须具有与较小结构相同(类型)的成员,以便正确读取值。

可能不建议在您自己的代码中执行此操作,编译器会抱怨类型不兼容。

于 2013-04-16T00:32:28.723 回答