C 一个结构如何通过类似“的方式映射到另一个结构?”;返回(结构a*)b“;

C 一个结构如何通过类似“的方式映射到另一个结构?”;返回(结构a*)b“;,c,struct,linux-kernel,kernel,C,Struct,Linux Kernel,Kernel,我试图理解linux内核网络代码,我遇到了很多函数,比如 static inline struct tcp_sock *tcp_sk(const struct sock *sk) { return (struct tcp_sock *)sk; } 结构sock和tcp_sock的内容有很大不同。这种映射究竟是如何发生的?具有相同名称和类型的结构成员是否相互映射 编辑1:更具体地说,在函数tcp\u v4\u connect中 struct tcp_sock *tp = tcp_

我试图理解linux内核网络代码,我遇到了很多函数,比如

static inline struct tcp_sock *tcp_sk(const struct sock *sk)
{
        return (struct tcp_sock *)sk;
}
结构
sock
tcp_sock
的内容有很大不同。这种映射究竟是如何发生的?具有相同名称和类型的结构成员是否相互映射

编辑1:更具体地说,在函数
tcp\u v4\u 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\u 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
时,如何将其值传递到函数


谢谢。

由于构造只是一个强制转换,因此没有“映射”任何内容,
sk
指向的内存位置没有实际更改任何内容

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

在linux内核代码中,您可以看到
struct sock
struct tcp_sock
具有
struct sock
的所有字段(
tcp_sock
包含
inet\u连接\u sock
,其中包含
inet\u sock
,然后分别包含
sock
作为第一个元素)。所以,“结构的内容……非常不同”,这是不完全正确的。它们实际上是相同的(至少对于
struct sock
的大小是相同的)

为了能够正确地执行此操作,系统以某种方式“必须知道”它可以安全地将
struct sock
强制转换为
struct tcp_sock
——此信息通常隐藏在公共标头的某个位置,在这种情况下,隐藏在
struct sock
部分中(我最近没有查过,但我想这里的信息在
sk_family

编辑后:

实际上传递给函数的是一个指向内存区域的指针。以前发生的任何事情都不会被cast更改(如我上面所说)。如果我们可以安全地假设,
sk
在某段时间之前是指向
struct tcp_sock
的指针,我们可以安全地将其转换回这样的野兽。这通常是在代码中完成的,该代码在具有泛型和特定部分的数据周围移动(如本例中)。所有套接字(tcp、UDP、泛型、Unix套接字等)数据具有在所有特定套接字结构开头的
struct sock
中收集的公共数据。因此,对于传入的套接字数据,该结构的所有通用部分首先由处理
struct sock
的函数处理,之后的函数必须有一些大型的
开关…case
,用于查看指定的ic部件,然后传递特定的指针类型


这允许采用分层的编程方法,首先将所有内容转换为通用的
struct sock
,然后由所有套接字类型的通用函数处理通用部分,然后将指针转换回原来的状态,并由专业函数处理特定部分。一直以来,内存基本上用作
struct sock
上的“背包”以保存特定数据的区域保持不变。

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

没有

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

现在,
struct sock
(套接字的网络层表示)将s
truct sock\u 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;
 90 struct inet_connection_sock {
 91         /* inet_sock has to be the first member! */
 92         struct inet_sock          icsk_inet;
struct-tcp\u-sock
struct-inet\u-connection\u-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

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;
 90 struct inet_connection_sock {
 91         /* inet_sock has to be the first member! */
 92         struct inet_sock          icsk_inet;
猜猜哪个struct是
inet\u 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\u conn.icsk_inet.sk
您正在访问我们的
sock
结构。

谢谢,这消除了我的一些无知。我刚刚编辑了这个问题来添加一些具体的细节,您能看一下吗?谢谢!我编辑了这个问题以获得更精确的怀疑。您也能看一下吗?sk就像我处理的一样在这段代码中,通过访问tp->write_seq,您正在通过write_seq成员位置访问sk offset地址处的内存,并且必须确保可以访问内存,因为序列号对于TCP来说是一个至关重要的变量,如何确保在多个函数调用期间保持不变(例如,从TCP connect转到TCP send)?我在代码中找不到任何关于保留内存的内容。通过仔细检查struct sock代表的网络连接类型,可以确定这一点。好的。我正在尝试对我的协议执行类似的操作。你能告诉我在代码中的何处确保分配给struct tcp_sock的内存没有被违反?或者我可以执行以下操作吗为我的协议创建一个类似的结构,并期望它像tcp\U sock一样工作?