将指向较大结构的指针转换为指向较小结构的指针

时间:2013-04-16 00:21:56

标签: c sockets pointers casting struct

这篇文章将以this one为基础,但会更加通用。

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

我将使用Socket API作为示例:

sockaddr_storage大于sockaddr,但指向sockaddr_storage的指针在传递给<{p>等函数之前会被转换为指向sockaddr的指针

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

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

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

然后像这样访问其成员?或者他们做了更复杂的事情?

3 个答案:

答案 0 :(得分:3)

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

基本上,sockaddr被定义为具有类型(sa_family),用于指定它实际拥有的内容,后跟一些数据。指向sockaddr的指针通常指向派生结构(sockaddr_*),该结构指定对数据的特定解释。

sockaddr_storage与普通sockaddr类似,因为它不包含特定的协议地址,只包含存储空间。区别在于sockaddr_storage指定的空间大于sockaddr,使其成为隐藏特定于协议的sockaddr的合适类型。

查看普通sockaddr的函数首先会查看sa_family,例如AF_INET(对于IPv4)或AF_INET6(对于IPv6)或其他内容,然后将指定的指针强制转换为适当的sockaddr子类型(例如,sockaddr_in用于IPv4) 。然后它可以检查addrlen以确保转换指针指向足够的空间来保存子类型。

答案 1 :(得分: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部分运行

答案 2 :(得分:0)

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

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