是否会围绕sockaddr_storage和sockaddr_in进行强制转换? [英] Will casting around sockaddr_storage and sockaddr_in break strict aliasing?

查看:147
本文介绍了是否会围绕sockaddr_storage和sockaddr_in进行强制转换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

围绕sockaddr_storage和sockaddr_in进行转换是否会破坏严格的别名?例如,在下面的代码中,我用一个类型为`sockaddr_in`的指针填充sockaddr_storage结构,然后将其传递给一个接受类型为`sockaddr`的指针的函数 -



Will casting around sockaddr_storage and sockaddr_in break strict aliasing? For example in the code below, I'm filling sockaddr_storage structure with a pointer of type `sockaddr_in` and then passing it to a function that accepts a pointer of type `sockaddr` -

sockaddr_storage addrStruct;
sockaddr_in * tmp = reinterpret_cast<struct sockaddr_in *> (&addrStruct);
tmp->sin_family = AF_INET;
tmp->sin_port = htons(port);
inet_pton(AF_INET, addr, tmp->sin_addr);

// int socket = socket(...);
// int error  = bind(socket, (sockaddr *)&addrStruct, sizeof(addrStruct));
// ...





以下是一些官方文档的说法 -



Microsoft的文档 -





Here's what some official documentation say -

Microsoft's documentation -

引用:

应用程序开发人员通常只使用SOCKADDR_STORAGE的ss_family成员。其余成员确保SOCKADDR_STORAGE可以包含IPv6或IPv4地址,并且适当填充结构以实现64位对齐。这种对齐使协议特定的套接字地址数据结构能够访问SOCKADDR_STORAGE结构中的字段而不会出现对齐问题。通过填充,SOCKADDR_STORAGE结构的长度为128个字节。

Application developers normally use only the ss_family member of the SOCKADDR_STORAGE. The remaining members ensure that the SOCKADDR_STORAGE can contain either an IPv6 or IPv4 address and the structure is padded appropriately to achieve 64-bit alignment. Such alignment enables protocol-specific socket address data structures to access fields within a SOCKADDR_STORAGE structure without alignment problems. With its padding, the SOCKADDR_STORAGE structure is 128 bytes in length.





Opengroup的文档 -





Opengroup's documentation -

Quote:

< sys / socket.h> header应定义sockaddr_storage结构。这个结构应该是:



- 大到足以容纳所有支持的协议特定的地址结构



- 在适当的边界对齐,以便指向它的指针可以作为指向协议特定地址结构的指针,并用于访问这些结构的字段而不会出现对齐问题

The <sys/socket.h> header shall define the sockaddr_storage structure. This structure shall be:

- Large enough to accommodate all supported protocol-specific address structures

- Aligned at an appropriate boundary so that pointers to it can be cast as pointers to protocol-specific address structures and used to access the fields of those structures without alignment problems





套接字的手册页 -





Man page of socket -

Quote:

此外,套接字API提供数据类型struct sockaddr_storage。此类型适用于容纳所有受支持的特定于域的套接字地址结构;它足够大并且正确对齐。 (特别是,它足以容纳IPv6套接字地址。)

In addition, the sockets API provides the data type struct sockaddr_storage. This type is suitable to accommodate all supported domain-specific socket address structures; it is large enough and is aligned properly. (In particular, it is large enough to hold IPv6 socket addresses.)





您还可以在SO threads



我尝试了什么:



我还推荐了另外两种方法 - 使用所有的联合结构,然后仅从该联合放置和检索值。但它也被认为是C99标准下的未定义行为。下一个看起来像这样 -





You can also see previous discussion at SO threads.

What I have tried:

There are two other methods that were recommended to me - using a union of all the structs and then putting and retrieving values to/back from that union only. But it is also said to be undefined behaviour under C99 standard. Next one looks like this -

struct sockaddr_in sin;

sin.sin_family = AF_INET;
sin.sin_port= htons(port);





首先我们在sockaddr_storage中创建所需的结构并填充它具有所需的值。然后我们将它记忆到sockaddr_storage结构 -





First we create the required structure to be filled in sockaddr_storage and fill it with required values. Then we memcpy it to sockaddr_storage structure -

memcpy(reinterpret_cast<char *>(&addrStruct),
       reinterpret_cast<char *>(&sin), sizeof(sin));

推荐答案

在提到的SO中已经说了很多线。但我不会太在乎。这是我的(有点实用)观点:



这些套接字结构有点特殊,因为 sockaddr 套接字函数的参数通常不会这样传递,而是通过转换适当的类型,如 sockaddr_in sockaddr_in6 。结构的第一个成员(系列)定义了如何解释传递的数据(因此也是传递结构的最大大小)。



所以铸造这是故意的(不要忘记套接字函数来自C标准库)。



通常声明所需类型的变量并通过将其转换为 sockaddr 。因此,当您只想传递IPv4结构时,不需要创建更大的结构。如果你必须在程序执行期间决定数据类型,你可以使用更大的结构,如 sockaddr_storage ,并像你已经完成或使用两个代码块一样使用匹配的结构在块内调用套接字函数。



无论如何都不需要复制数据。



BTW:没有必要在这里施放:

There has been already much said in the mentioned SO thread. But I would not care too much. Here is my (a bit pragmatic) view:

These socket structures are a little bit special because the sockaddr parameter of the socket functions is usually never passed as such but by casting an appropriate type like sockaddr_in or sockaddr_in6. The first member of the structures (the family) defines how the passed data will be interpreted (and therefore also the max. size of the passed struct).

So casting here is by intention (don't forget that the socket functions are from the C standard library).

It is common to declare a variable of the required type and pass that casting it to sockaddr. So there is no need to create a larger struct when you only want to pass an IPv4 struct for example. If you would have to decide the data type during program execution you can use a larger struct like sockaddr_storage and cast that like you have done or use two code blocks with the matching structs and call the socket function within the block.

In any case there should be no need to copy the data.

BTW: There is no need to cast here:
memcpy(reinterpret_cast<char *>(&addrStruct),
       reinterpret_cast<char *>(&sin), sizeof(sin));

memcpy 参数是 void * 而不是 char *


这篇关于是否会围绕sockaddr_storage和sockaddr_in进行强制转换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆