一种结构如何通过 "return (struct a *) b" 之类的东西映射到另一种结构

How is one structure mapped to another by something like "return (struct a *) b"

我正在尝试理解 linux 内核网络代码,我遇到了很多函数,例如

static inline struct tcp_sock *tcp_sk(const struct sock *sk)
{
        return (struct tcp_sock *)sk;
}

结构socktcp_sock的内容大不相同。这种映射究竟是如何发生的?具有相同名称和类型的结构成员是否相互映射?

编辑 1: 更具体地说,在函数 tcp_v4_connect

struct tcp_sock *tp = tcp_sk(sk);
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
                           inet->inet_daddr,
                           inet->inet_sport,
                           usin->sin_port);
err = tcp_connect(sk);

然后在上面调用的函数tcp_connect中,

struct tcp_sock *tp = tcp_sk(sk);
tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);

变量 write_seq 仅存在于 struct tcp_sock 中,那么当只有 struct sock *sk 传递给它时,它的值如何传递给函数 tcp_connect

谢谢。

由于构造只是一个 cast,"mapped" 没有任何内容,sk 指向的内存位置实际上没有任何更改。

这仅在结构相似或至少以相同偏移量的相同字段开始时才有效。

在 linux 内核代码中,您可以看到 struct sockstruct tcp_sock 具有 struct sock 的所有共同字段(tcp_sock 包含一个 inet_connection_sock 其中包含一个 inet_sock,后者又分别包含一个 sock 作为第一个元素)。所以,“结构的内容...完全不同”,并不完全正确。它们实际上是相同的(至少对于 struct sock 的大小)。

为了能够正确执行此操作,系统以某种方式 "must know" 可以安全地将 struct sock 转换为 struct tcp_sock - 此信息通常隐藏在常见 header,在本例中是 struct sock 部分(我最近没有检查,但我猜这里的信息在 sk_family

编辑后:

实际传递给您的函数的是指向内存区域的指针。无论以前发生过什么,都没有被演员改变(正如我上面所说的)。如果我们可以安全地假设 sk 之前某个时间是指向 struct tcp_sock 的指针,我们就可以安全地将它转换回这样的野兽。这通常在代码中完成,该代码围绕具有 genericspecific 部分的数据移动(如本例所示)。所有套接字(TCP、UDP、通用、Unix 套接字...)数据都有公共数据,这些数据收集在所有特定套接字结构开头的 struct sock 中。因此,在传入的套接字数据上,该结构的所有通用部分首先由处理 struct sock 的函数处理,后面必须有一些大的 switch...case 查看特定部分,然后传递特定 指针类型。

这允许一种 layered 编程方法,其中所有内容首先转换为通用 struct sock,然后通用部分由所有套接字类型通用的函数处理,稍后,指针是恢复到 原来的状态 ,具体部分由专门的函数处理。一直以来,基本上用作 struct sock 上的 "backpack" 来保存特定数据的内存区域只是保持不变。

具有相同名称和类型的结构成员是否相互映射?

没有

struct sock sk; /* our sock struct */
struct tcp_sock *tcp_sk = (struct tcp_sock *)&sk;

tcp_sk 指针现在简单地指向 &sk 指向的内存。现在通过访问 tcp_sk 字段,您将访问分配给该指针的内存,但为了获得预期结果,存储在两个地址的数据应该有效。

现在,struct sock(套接字的网络层表示)的第一个成员是 struct sock_common

306 struct sock {
307         /*
308          * Now struct inet_timewait_sock also uses sock_common, so please just
309          * don't add nothing before this first member (__sk_common) --acme
310          */
311         struct sock_common      __sk_common;

并且 struct tcp_sockstruct inet_connection_sock 作为第一个成员

struct tcp_sock {
138         /* inet_connection_sock has to be the first member of tcp_sock */
139         struct inet_connection_sock     inet_conn;

并且此结构的第一个成员为 struct inet_sock

 90 struct inet_connection_sock {
 91         /* inet_sock has to be the first member! */
 92         struct inet_sock          icsk_inet;

猜猜 inet_sock 的第一个成员是什么结构...它是 struct sock:

172 struct inet_sock {
173         /* sk and pinet6 has to be the first two members of inet_sock */
174         struct sock             sk;

因此,通过访问 tcp_sk.inet_conn.icsk_inet.sk,您正在访问我们的 sock 结构。