这篇文章将以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
!”
然后像这样访问其成员?或者他们做了更复杂的事情?
答案 0 :(得分:3)
sockaddr
是C的穷人多态性成语的完美例子。在OO语言中,sockaddr
将是一个基类,大量协议地址类型(sockaddr_in
,sockaddr_in6
,sockaddr_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)
我的猜测是函数只是不关心,如果结构指向大于预期读取它至少不会给出访问冲突。当然,较大结构的第一部分必须具有与较小结构相同(类型)的成员,以便正确读取值。
可能不建议在您自己的代码中执行此操作,编译器会抱怨不兼容的类型。