当我使用一些看起来像的代码时,编译器会产生这个警告。
.... 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
。 警告来自陈述:
所有我想知道的是导致此警告的原因,如果这不是正确的做法, 我该怎么做才能纠正它。 我可以在这里使用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*
转换为sockaddr_in*
更改对齐要求,并且通过新指针访问对象甚至会违反别名规则并导致未定义的行为。
为什么你可以忽略它 :
在您的情况下,对象p->ai_addr
指向,最有可能是sockaddr_in
或sockaddr_in6
对象(通过检查ai_family
确定),因此操作是安全的。 但是,编译器不知道并产生警告。
它与使用static_cast
将指向基类的指针static_cast
转换为指向派生类的指针基本相同 – 在一般情况下它是不安全的,但如果你知道外部的正确动态类型,它就是明确定义的。
解:
我不知道一个干净的方法(除了抑制警告),这通过 -Weverything
启用警告并不罕见。您可以将 p->ai_addr
指向的对象p->ai_addr
字节复制到相应类型的对象,但随后您可能(很可能)不再像以前那样使用addr
,因为它现在指向不同的(例如,本地)变量。
-Weverything
无论如何,我不会将其用于我常用的版本,因为它会增加太多的噪音,但如果你想保留它,@ Kurt Stutsman在评论中提到了一个很好的解决方案:
clang ++(g ++在任何情况下都不会发出警告)如果使用reinterpret_cast
代替c样式转换(你不应该使用它),它不会发出警告,尽管两者都有(在这种情况下)相同的function。 也许是因为reinterpret_cast
明确告诉编译器: “相信我,我知道,我在做什么” 。
旁边注意:在c ++代码中,您不需要struct
关键字。
嗯 – -Weverything
发出很多警告,其中一些警告会发出不必要的警告。
在这里,您的代码会触发强制显示的cast-align
警告
从…转换为……从…增加所需的对齐…
这就是这种情况,因为struct addr
struct addr_in
只有2,而struct addr_in
则为4。
但是你 (以及getaddrinfo
的程序员……)知道指针p->ai_addr
已经指向一个实际的struct addr_in
,所以转换是有效的。
你可以:
我必须承认,我很少使用-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 .... }
详细说明memcpy版本。 我认为这是ARM所必需的,它不能有错误的数据。
我创建了一个只包含前两个字段的结构(我只需要端口)
struct sockaddr_in_header { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ };
然后,为了获得端口,我使用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上的端口有关
如何在arm上将sockaddr指针强制转换为sockaddr_in
能够认为与此问题相同的权力,但我不想忽视警告。 经验告诉我这是一个坏主意。
以上就是c/c++开发分享从sockaddr *转换为sockaddr_in *增加了所需的对齐相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/559765.html