C++ 从sockaddr*到sockaddr_in*的强制转换增加了所需的对齐
当我处理某些代码时,编译器会生成此警告,这些代码看起来像-C++ 从sockaddr*到sockaddr_in*的强制转换增加了所需的对齐,c++,linux,networking,casting,clang,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 = (stru
....
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\u in
和sockaddr\u in 6
。警告来自以下声明:
ipv4中的struct sockaddr_=(struct sockaddr_in*)p->ai_addr代码>
struct sockaddr\u in6*ipv6=(struct sockaddr\u in6*)p->ai\u addr代码>
静态\u cast
/动态\u cast
/重新解释\u cast
吗
从“StutoSokAddRe*”到“StutoSokAddRy**”的精确警告增加了所需的对齐方式,从2到4 .< /P> < P> <强> TLDR:< /强>此警告不表示代码中的错误,但您可以通过使用POPER C++ +CODE > RealTytRasks< /Cuff>(谢谢@ Kurt Stutsman)来避免它。
说明: 警告原因:
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
....
}
由一个无符号短字符(通常为16位)和一个字符数组组成,因此其对齐要求为2李>sockaddr
包含(除其他外)一个sockaddr\u in
的对齐要求为4,这意味着struct in\u addr
也必须对齐到4字节边界sockaddr\u in
sockaddr*
强制转换为*中的sockaddr\u会更改对齐要求,通过新指针访问对象甚至会违反别名规则并导致未定义的行为
为什么可以忽略它:
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
....
}
在您的情况下,p->ai_addr
所指向的对象很可能是sockaddr\u In
或sockaddr\u In 6
对象(通过检查ai_族
确定),因此操作是安全的。但是,编译器不知道这一点,并生成警告
它本质上与使用static\u cast
将指向基类的指针转换为指向派生类的指针是一样的——在一般情况下,这是不安全的,但是如果您从外部知道正确的动态类型,它是定义良好的
解决方案:
我不知道有什么方法可以解决这个问题(除了抑制警告),这在-Weverything
启用警告时并不罕见。您可以将p->ai_addr
所指向的对象逐字节复制到相应类型的对象,但是您(很可能)可以不再像以前那样使用addr
,因为它现在将指向不同的(例如本地)变量。
-Weverything
无论如何,我不会在我的常规版本中使用,因为它添加了太多的噪音,但是如果你想保留它,@Kurt Stutsman在评论中提到了一个很好的解决方案:
clang++(g++在任何情况下都不会发出警告)不会发出警告,如果您使用reinterpret_cast
而不是c样式的cast(无论如何都不应该使用),尽管两者(在本例中)具有完全相同的功能。可能是因为reinterpret\u cast
明确地告诉编译器:“相信我,我知道我在做什么”
在C++代码中,你不需要<代码>结构> <代码>关键字。 < p>井>代码> -WeviyToest< /Cord>可以进行相当多的警告。
在这里,您的代码将触发强制对齐
警告,该警告明确表示
由…铸造。。。到从…增加所需的对齐。。。到
这里就是这种情况,因为struct addr
的对齐度只有2,而struct addr\u的对齐度是4
但是您(以及getaddrinfo
的程序员)知道指针p->ai_addr
已经指向了中的实际结构addr\u,因此强制转换是有效的
您可以:
- 让警告触发并忽略它-毕竟它只是一个警告
- 在
-Weverything
我必须承认,出于这个原因,我很少使用-Weverything
,而只使用-Wall
或者,如果您知道您只使用了叮当声,您可以使用来明确地仅在这些行上打开警告:
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
....
}
详细说明memcpy版本。我认为这是ARM所需要的,因为ARM不能有错配的数据
我创建了一个只包含前两个字段的结构(我只需要端口)
然后,为了取出端口,我使用memcpy将数据移动到堆栈中
struct sockaddr_in_header sinh;
unsigned short sin_port;
memcpy(&sinh, conn->local_sockaddr, sizeof(struct sockaddr_in_header));
然后返回港口
sin_port = ntohs(sinh.sin_port);
这个答案实际上与Arm上的端口有关
列强认为这和这个问题是同一个问题,但我不想忽视警告。经验告诉我这是个坏主意。p
和res
看起来像是具有struct addrinfo
类型,不是吗?无论如何,演员组在我的平台上没有发出任何警告(OSX,clang 700.1.81)。请精确说明您的问题。哦,好的,您正在使用-Wcast align
,对吗?为了避免它,您应该使用memcpy
例如,打破别名规则是UB。@Jean BaptisteYunès-Wall-Weverything
。然而,我不明白我应该如何在这里使用memcpy,如何打破别名?期待答案:)我会说对齐,而不是别名。