从sockaddr *强制转换为sockaddr_in *增加所需的对齐方式 [英] 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);
}
....
}
其中,p = res
的类型为struct addrinfo
,产生警告的类型为sockaddr_in
和sockaddr_in6
.警告来自以下语句:
where p = res
are of type struct addrinfo
and the types producing warnings are sockaddr_in
and 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;
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
我想知道的是导致的原因,以及如果这不是正确的处理方法,我可以做什么 进行纠正.我可以在这里使用static_cast
/dynamic_cast
/reinterpret_cast
中的任何一个吗?
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?
确切的警告是-cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4
.
推荐答案
TLDR:此警告并不表示您的代码中有错误,但是您可以通过使用poper c ++
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).
说明:
警告原因:
-
sockaddr
由一个无符号的short(通常为16位)和一个char数组组成,因此其对齐要求为2. -
sockaddr_in
包含(除其他事项外)struct in_addr
,其对齐要求为4,这又意味着sockaddr_in
也必须对齐4字节边界.
sockaddr
consists of a unsigned short (usually 16 bit) and a char array, so its alignment requirement is 2.sockaddr_in
contains (among other things) astruct in_addr
which has an alignment requirement of 4 which in turn meanssockaddr_in
also must be aligned to a 4 Byte boundary.
因此,将任意sockaddr*
强制转换为sockaddr_in*
会更改对齐要求,并且通过新指针访问对象甚至会违反别名规则,并导致未定义的行为.
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.
为什么您可以忽略它:
在您的情况下,对象p->ai_addr
指向的对象,很可能还是sockaddr_in
或sockaddr_in6
对象(通过检查ai_family
确定),因此该操作是安全的.但是,您的编译器不知道这一点,并且会产生警告.
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. However you compiler doesn't know that and produces a warning.
与使用static_cast
将基类的指针强制转换为派生类的指针本质上是相同的-在通常情况下这是不安全的,但是如果您本能地知道正确的动态类型,则它是不安全的定义明确.
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.
解决方案:
我不知道有什么解决方法(除了消除警告),这对于 -Weverything
启用的警告并不罕见.您可以逐字节地将p->ai_addr
指向的对象复制到适当类型的对象,但是您(很可能)不再像以前那样使用addr
了,因为它现在指向另一个(例如本地)变量.
无论如何,-Weverything
都不是我要使用的东西,因为它会增加太多的噪音,但是如果您想保留它,@Kurt Stutsman在评论中提到了一个很好的解决方案:
Solution:
I don't know a clean way around this (other than suppress the warning), which is not unusual with warnings enabled by -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 (e.g. local) variable.
-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:
clang ++(在任何情况下g ++都不会发出警告)不会发出警告,尽管两者都具有(在这种情况下)完全相同的功能.也许是因为reinterpret_cast
明确告诉编译器:相信我,我知道我在做什么" .
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. Maybe because reinterpret_cast
explicitly tells the compiler: "Trust me, I know, what I'm doing" .
另一方面,在c ++代码中,您不需要struct
关键字.
On a side Note: In c++ code you don't need the struct
keywords.
这篇关于从sockaddr *强制转换为sockaddr_in *增加所需的对齐方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!