Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从sockaddr*到sockaddr_in*的强制转换增加了所需的对齐_C++_Linux_Networking_Casting_Clang - Fatal编程技术网

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

....
}
  • sockaddr
    由一个无符号短字符(通常为16位)和一个字符数组组成,因此其对齐要求为2
  • sockaddr\u in
    包含(除其他外)一个
    struct in\u addr
    的对齐要求为4,这意味着
    sockaddr\u in
    也必须对齐到4字节边界
因此,将任意
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,如何打破别名?期待答案:)我会说对齐,而不是别名。