How to cast sockaddr_storage and avoid breaking strict-aliasing rules

后端 未结 4 963
情书的邮戳
情书的邮戳 2020-12-12 22:57

I\'m using Beej\'s Guide to Networking and came across an aliasing issue. He proposes a function to return either the IPv4 or IPv6 address of a particular struct:



        
4条回答
  •  星月不相逢
    2020-12-12 23:12

    The issue has nothing to do with the call to the function. Rather, it's with ((struct sockaddr_in*)sa)->sin_addr. The problem is that sa is a pointer of one type, but you're casting it to a pointer of a different type and then dereferencing it. This breaks a rule called "strict aliasing", which says that variables of different types can never alias. In your case, aliasing to a different type is exactly what you want to do.

    The simple solution is to turn off this optimization, which allows aliasing in this manner. On GCC, the flag is -fno-strict-aliasing.

    The better solution is to use a union, as mentioned by Nikolai.

    void *get_in_addr(struct sockaddr *sa)
    {
        union {
            struct sockaddr     *sa;
            struct sockaddr_in  *sa_in;
            struct sockaddr_in6 *sa_in6;
        } u;
        u.sa = sa;
        if (sa->sa_family == AF_INET)
            return &(u.sa_in->sin_addr);
        else
            return &(u.sa_in6->sin6_addr);
    }
    

    That said, I can't actually get GCC to give me a warning when using your original code, so I'm not sure if this buys you anything.

提交回复
热议问题