如何投射sockaddr_storage并避免违反严格别名规则

sin*_*oth 24 c sockets strict-aliasing pointer-aliasing

我正在使用Beej的网络指南,并遇到了一个别名问题.他提出了一个函数来返回特定结构的IPv4或IPv6地址:

1  void *get_in_addr( struct sockaddr *sa )
2  {
3      if (sa->sa_family == AF_INET)
4        return &(((struct sockaddr_in*)sa)->sin_addr);
5      else
6        return &(((struct sockaddr_in6*)sa)->sin6_addr);
7  }
Run Code Online (Sandbox Code Playgroud)

这会导致GCC 在第3行为sa吐出严格别名错误.据我所知,这是因为我这样调用这个函数:

struct sockaddr_storage their_addr;
...
inet_ntop(their_addr.ss_family,
          get_in_addr((struct sockaddr *)&their_addr),
          connection_name,
          sizeof connection_name);
Run Code Online (Sandbox Code Playgroud)

我猜测别名与their_addr变量是类型的事实有关,sockaddr_storage而另一个不同类型的指针指向同一个内存.

就是要解决这个症结的最佳方式sockaddr_storage,sockaddr_in以及sockaddr_in6组成工会?看起来这应该是网络中的一个很好的领域,我只是找不到任何有最佳实践的好例子.

此外,如果有人能够准确解释别名问题发生的位置,我会非常感激.

Nik*_*sov 21

我倾向于这样做以使GCC使用类型惩罚做正确的事情,这在工会中是明确允许的:


/*! Multi-family socket end-point address. */
typedef union address
{
    struct sockaddr sa;
    struct sockaddr_in sa_in;
    struct sockaddr_in6 sa_in6;
    struct sockaddr_storage sa_stor;
}
address_t;
Run Code Online (Sandbox Code Playgroud)

  • 联盟可能是为此而发明的,我同意编译器应该处理它.但该标准没有具体说明.支持它是gcc提供的额外保证,因此它可能在另一个编译器上失败,编译器的开发人员会认为它们是正确的.在未来,gcc开发人员可以做同样的事情.在C世界中,趋势是打破现有的编程实践,在速度基准测试中获得0.5%,严格的混叠本身只是这种趋势的一个例子. (4认同)
  • 我似乎记得POSIX保留了以_t结尾的类型的名称.抱歉迂腐. (4认同)
  • C99标准专门允许工会用于此目的.见http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf§6.5,第7段. (3认同)
  • @NikolaiNFetissov"_union是为了这个而发明的"来源?这是对'union`的误用! (2认同)