[英]cast from sockaddr * to sockaddr_in * increases required alignment
The compiler produces this warning when I'm working with some code which looks like - 当我使用某些看起来像这样的代码时,编译器会产生此警告:
....
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer = "IPv0";
if(p->ai_family == AF_INET) {
ipVer = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else {
ipVer = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
....
}
where p = res
are of type struct addrinfo
and the types producing warnings are sockaddr_in
and sockaddr_in6
. 其中
p = res
的类型为struct addrinfo
,产生警告的类型为sockaddr_in
和sockaddr_in6
。 The warning comes from statements : 警告来自以下语句:
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
All I want to know is what is causing this warning and what can I do to correct it if this is not the proper way to do things. 我只想知道是什么导致此警告,如果这不是正确的处理方法, 我该怎么办才能纠正它。 Could I use any of
static_cast
/ dynamic_cast
/ reinterpret_cast
here? 我可以在这里使用任何
static_cast
/ dynamic_cast
/ reinterpret_cast
吗?
The exact warning is - cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4
. 确切的警告是 -
cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4
。
TLDR: This warning doesn't indicate an error in your code, but you can avoid it by using a poper c++ reinterpret_cast
(thanks to @Kurt Stutsman). TLDR:此警告并不表示您的代码中有错误,但是您可以使用poper c ++
reinterpret_cast
(由于@Kurt Stutsman)来避免此错误。
Explanation: 说明:
Reason for the warning : 警告的原因 :
sockaddr
consists of a unsigned short (usually 16 bit) and a char array, so its alignment requirement is 2. sockaddr
由一个无符号的short(通常为16位)和一个char数组组成,因此其对齐要求为2。 sockaddr_in
contains (among other things) a struct in_addr
which has an alignment requirement of 4 which in turn means sockaddr_in
also must be aligned to a 4 Byte boundary. sockaddr_in
包含(除其他外) struct in_addr
,其对齐要求为4,这又意味着sockaddr_in
也必须对齐4字节边界。 For that reason, casting an arbitrary sockaddr*
to an sockaddr_in*
changes the alignment requirement, and accessing the object via the new pointer would even violate aliasing rules and result in undefined behavior. 因此,将任意
sockaddr*
强制转换为sockaddr_in*
更改对齐要求,并且通过新指针访问对象甚至会违反别名规则,并导致未定义的行为。
Why you can ignore it : 为什么您可以忽略它 :
In your case, the object, p->ai_addr
is pointing to, most likely is a sockaddr_in
or sockaddr_in6
object anyway (as determined by checking ai_family
) and so the operation is safe. 在您的情况下,对象
p->ai_addr
指向, p->ai_addr
都很可能是sockaddr_in
或sockaddr_in6
对象(通过检查ai_family
确定),因此该操作是安全的。 However you compiler doesn't know that and produces a warning. 但是,您的编译器不知道并生成警告。
It is essentially the same thing as using a static_cast
to cast a pointer to a base class to a pointer to a derived class - it is unsafe in the general case, but if you know the correct dynamic type extrinsically, it is well defined. 这与使用
static_cast
将指向基类的指针static_cast
转换为派生类的指针本质上是相同的-在通常情况下这是不安全的,但是如果您在外部了解正确的动态类型,则定义明确。
Solution: 解:
I don't know a clean way around this (other than suppress the warning), which is not unusual with warnings enabled by -Weverything
.我不知道有什么解决方法(除了抑制警告),这与 -Weverything
启用的警告并不罕见。You could copy the object pointed to by p->ai_addr
byte by byte to an object of the appropriate type, but then you could (most likely) no longer use addr
the same way as before, as it would now point to a different (eg local) variable.您可以将 p->ai_addr
指向的对象一个字节一个字节地复制到适当类型的对象,但随后(很有可能)不再像以前那样使用addr
了,因为它现在指向不同的(例如局部变量。
-Weverything
isn't something I would use for my usual builds anyway, because it adds far too much noise, but if you want to keep it, @Kurt Stutsman mentioned a good solution in the comments: -Weverything
无论如何,我无论如何都不会使用任何东西,因为它会增加太多噪音,但是如果您想保留它,@ Kurt Stutsman在评论中提到了一个很好的解决方案:
clang++ (g++ doesn't emit a warning in any case) doesn't emit a warning, if you use a reinterpret_cast
instead of the c style cast (which you shouldn't use anyway), although both have (in this case) exactly the same functionality. 如果您使用
reinterpret_cast
而不是c样式强制转换(无论如何都不应使用),则clang ++(g ++在任何情况下均不会发出警告)不会发出警告,尽管两者都(在这种情况下)完全相同相同的功能。 Maybe because reinterpret_cast
explicitly tells the compiler: "Trust me, I know, what I'm doing" . 也许是因为
reinterpret_cast
明确告诉编译器: “相信我,我知道我在做什么” 。
On a side Note: In c++ code you don't need the struct
keywords. 附带说明:在c ++代码中,您不需要
struct
关键字。
Well -Weverything
enables quite a lot of warnings some of them are known to throw unwanted warnings. 很好-
-Weverything
启用很多警告,其中一些警告会引发不必要的警告。
Here your code fires the cast-align
warning, that says explicitely 在这里,您的代码会触发
cast-align
警告,即明确表示
cast from ... to ... increases required alignment from ... to ...
从...转换为...将所需的对齐方式从...转换为...
And it is the case here because the alignement for struct addr
is only 2 whereas it is 4 for struct addr_in
. 这是因为
struct addr
struct addr_in
方式只有2而struct addr_in
是4。
But you (and the programmer for getaddrinfo
...) know that the pointer p->ai_addr
already points to an actual struct addr_in
, so the cast is valid. 但是您 (以及
getaddrinfo
的程序员)知道指针p->ai_addr
已经指向实际的struct addr_in
,因此struct addr_in
有效。
You can either: 您可以:
-Wno-cast-align
after -Weverything
-Wno-cast-align
后将其-Wno-cast-align
-Weverything
I must admit that I seldom use -Weverything
for that reason, and only use -Wall
我必须承认,出于这个原因,我很少使用
-Weverything
,而仅使用-Wall
Alternatively, if you know that you only use CLang, you can use pragmas to explicetely turn the warning only on those lines : 另外,如果您知道仅使用CLang,则可以使用编译指示 仅在这些行上明确打开警告:
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer = "IPv0";
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
if(p->ai_family == AF_INET) {
ipVer = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else {
ipVer = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
#pragma clang diagnostic pop
....
}
To elaborate on the memcpy version. 详细介绍一下memcpy版本。 I thnk this is needed for ARM which cannot have misalligned data.
我想这对于不会产生错误数据的ARM是必需的。
I created a struct that contains just the first two fields (I only needed port) 我创建了仅包含前两个字段的结构(我只需要端口)
struct sockaddr_in_header {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
};
Then to get the port out, I used memcpy to move the data to the stack 然后要移出端口,我使用了memcpy将数据移到堆栈中
struct sockaddr_in_header sinh;
unsigned short sin_port;
memcpy(&sinh, conn->local_sockaddr, sizeof(struct sockaddr_in_header));
And return the port 并返回端口
sin_port = ntohs(sinh.sin_port);
This answer is really related to getting the port on Arm 这个答案确实与获得Arm的端口有关
How do I cast sockaddr pointer to sockaddr_in on Arm 如何在Arm上将sockaddr指针转换为sockaddr_in
The powers that be think that to be the same question as this one, however I dont want to ignore warnings. 认为与这个问题相同的权力,但是我不想忽略警告。 Experience has taught me that is a bad idea.
经验告诉我,这是一个坏主意。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.