我正在尝试进行Socket编程,并在https://www.tenouk.com/Module43a.html上遇到了一篇文章,我很难理解将char数组如何转换为结构指针
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
根据我的理解,指针ip现在将保存缓冲区的地址,而struct ipheader成员的值现在将存储在缓冲区中。请帮助理解相同的。如果我是对的,那我们将如何打印存储在缓冲区中的值?
答案 0 :(得分:3)
您的理解是正确的。指针* ip将指向缓冲区。 char buffer [PCKT_LEN]是一个大小为sizeof(char)* PCKT_LEN的数组。由于char通常为1个字节长,因此它只是PCKT_LEN个字节的内存块。 PCKT_LEN定义为8192
存储struct ipheader所需的字节数远少于此。尝试使用int a = sizeof(ipheader)
并使用调试器查看分配给a
的值。对我来说,它是24个字节,但是对您来说可能略有不同。这意味着缓冲区可以容纳的数据超过了struct ipheader所需的数据。我没有深入研究代码,对套接字编程也不太了解。但是,这样做的一种用途可能是在结构外部添加额外的数据来增加缓冲区。因为您知道struct ipheader占用了sizeof(ipheader)个字节,所以您将获得sizeof(char)* 8192-剩下的sizeof(ipheader)可以增加数组。
编辑: 进一步检查后,这就是正在发生的情况:
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
它将尝试将ip标头存储在缓冲区的开头,然后使用udp标头扩展该缓冲区。通过使用buffer + sizeof(struct ipheader)
它通过将缓冲区偏移sizeof(struct ipheader)个字节来确保它在ipheader之后存储udp头。基本上struct ipheader *ip
指向缓冲区的开始,struct udpheader *udp
指向buffer + sizeof(struct ipheader)
。我希望这是有道理的。显然,缓冲区中还有很多空间,因此您有可能进一步扩大它。
答案 1 :(得分:1)
如何将char数组转换为结构指针
您不能安全地这样做。该代码调用未定义的行为:
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
该代码违反了the strict aliasing rule。基本上,这意味着不是某种对象类型的内存不能被视为该类型的对象,除了任何非char
对象可以被视为char
的数组之外
这不是发布的代码中发生的事情。在发布的代码中,char
数组被视为struct ipheader
。
内存不是struct ipheader
,而是char
的数组,因此代码违反了严格的别名。
从char *
到struct ipheader *
的转换也可能导致对象对齐不正确并违反6.3.2.3 Pointers, paragraph 7:
指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未针对引用类型正确对齐,则该行为未定义。 ...
不幸的是,您在这里发现的这样的代码太普遍了,因为基于x86的计算机是程序员广泛使用的最常见的平台,它们非常宽容错位的访问,因此这些代码倾向于“工作”。
请参见Structure assignment in Linux fails in ARM but succeeds in x86,以了解无法使用的平台示例。