从sockaddr *强制转换为sockaddr_in *增加所需的对齐方式 [英] cast from sockaddr * to sockaddr_in * increases required alignment

查看:512
本文介绍了从sockaddr *强制转换为sockaddr_in *增加所需的对齐方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用一些看起来像-

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_insockaddr_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 ++ (感谢@Kurt Stutsman).

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) 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*强制转换为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_insockaddr_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆