Abh*_*yal 5 c++ linux networking casting clang
当我使用一些看起来像的代码时,编译器会产生此警告.
....
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);
}
....
}
Run Code Online (Sandbox Code Playgroud)
其中p = res
是式的struct addrinfo
,并产生警告类型是sockaddr_in
和sockaddr_in6
.警告来自陈述:
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
这里的任何一个吗?
确切的警告是 - cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4
.
TLDR:此警告并不表示代码中存在错误,但您可以通过使用poper c ++来避免它reinterpret_cast
(感谢@Kurt Stutsman).
说明:
警告原因:
sockaddr
由无符号短(通常为16位)和char数组组成,因此其对齐要求为2. sockaddr_in
包含(其中包括)struct in_addr
具有4的对齐要求的a ,其又意味着sockaddr_in
还必须与4字节边界对齐.出于这个原因,强制转换sockaddr*
为sockaddr_in*
更改对齐要求,并通过新指针访问对象甚至会违反别名规则并导致未定义的行为.
为什么你可以忽略它:
在您的情况下,对象p->ai_addr
指向,最有可能是一个sockaddr_in
或sockaddr_in6
对象(通过检查确定ai_family
),因此操作是安全的.但是,编译器不知道并生成警告.
它与使用a static_cast
将指向基类的指针强制转换为指向派生类的指针基本相同- 在一般情况下它是不安全的,但如果你知道外部的正确动态类型,它就是很好定义的.
解决方案:
我不知道一个干净的方法(除了抑制警告),这在启用警告的情况下并不罕见-Weverything
.您可以将逐p->ai_addr
字节指向的对象复制到相应类型的对象,但随后您可能(很可能)不再使用addr
与之前相同的方式,因为它现在指向不同的(例如本地)变量.
-Weverything
不管怎样我不会用于我常用的版本,因为它会增加太多噪音,但如果你想保留它,@ Kurt Stutsman在评论中提到了一个很好的解决方案:
clang ++(g ++在任何情况下都不会发出警告)不发出警告,如果你使用的reinterpret_cast
不是c样式演员(你不应该使用它),尽管两者都(在这种情况下)完全是相同的功能.也许是因为reinterpret_cast
明确告诉编译器:"相信我,我知道,我在做什么".
另一方面注意:在c ++代码中,您不需要struct
关键字.
很好地-Weverything
发出了很多警告,其中一些警告会发出不必要的警告.
在这里,您的代码会触发cast-align
警告,明确说明
从...转换为......增加从......到...的所需对齐
这就是这种情况,因为对齐struct addr
只有2,而它是4 struct addr_in
.
但是你(以及getaddrinfo
...... 的程序员)知道指针p->ai_addr
已经指向实际struct addr_in
,所以转换是有效的.
你可以:
-Wno-cast-align
后-Weverything
我必须承认,我很少-Weverything
因为这个原因而使用,而且只能使用-Wall
或者,如果您知道仅使用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
....
}
Run Code Online (Sandbox Code Playgroud)