【问题标题】:Casting pointers to larger structs to pointers to smaller structs将指向较大结构的指针转换为指向较小结构的指针
【发布时间】:2013-04-16 00:21:55
【问题描述】:

这篇文章将以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!”

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

【问题讨论】:

    标签: c sockets pointers casting struct


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 感谢您的帮助!当您说“sockaddr 和 sockaddr_storage 不保存地址,只保存存储空间”时,您是什么意思?不是地址的存储空间吗?
    • 有点不清楚。我的意思是sockaddr 和sockaddr_storage 没有定义为保存任何特定 协议地址,而只是定义为保存一些数据。该数据被适当的sockaddr_* 类型解释为地址。
    • 再次感谢您!非常直接和彻底的答案。
    【解决方案2】:

    @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 部分进行操作

    【讨论】:

      【解决方案3】:

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

      可能不建议在您自己的代码中这样做,编译器会抱怨类型不兼容。

      【讨论】:

        猜你喜欢
        • 2015-01-24
        • 2020-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-21
        • 2012-03-28
        相关资源
        最近更新 更多