POSIX beabsichtigt, Zeiger auf Variationen von struct sockaddr
gießbar zu machen, jedoch kann dies je nach Interpretation des C-Standards eine Verletzung der strengen Aliasing-Regel und daher UB sein. (Siehe this answer mit Kommentaren darunter.) Ich kann zumindest bestätigen, dass es zumindest ein Problem mit gcc sein kann: Dieser Code druckt Bug!
mit Optimierung aktiviert ist, und Yay!
mit Optimierung deaktiviert:Wie legal Typ-Punning mit Unionen zu verwenden, um zwischen Variationen von struct Sockaddr zu übertragen, ohne die strenge Aliasing-Regel zu verletzen?
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
sa_family_t test(struct sockaddr *a, struct sockaddr_in *b)
{
a->sa_family = AF_UNSPEC;
b->sin_family = AF_INET;
return a->sa_family; // AF_INET please!
}
int main(void)
{
struct sockaddr addr;
sa_family_t x = test(&addr, (struct sockaddr_in*)&addr);
if(x == AF_INET)
printf("Yay!\n");
else if(x == AF_UNSPEC)
printf("Bug!\n");
return 0;
}
dies beachten Verhalten auf einem online IDE.
Um dieses Problem zu umgehen this answer schlägt die Verwendung von Typ punning mit Gewerkschaften:
/*! 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;
aber anscheinend sind die Dinge noch nicht so einfach, wie sie aussehen ... this comment von @zwol Zitiert:
Das kann arbeiten, aber braucht ein gutes Stück Sorgfalt. Mehr als ich in dieses Kommentarfeld passen kann.
Welche Art von gerechtes bisschen Sorgfalt dauert es? Was sind die Fallstricke der Verwendung von Typ Punning mit Gewerkschaften zwischen Varianten von struct sockaddr
zu werfen?
Ich bevorzuge zu fragen, als in UB zu laufen.
Es ist nicht klar, was Sie eigentlich mit der "Union" prowpem ist. Wie wäre es mit einem [MCVE] und mehr Details über Ihre Bedenken? Warum fragst du nicht zwol was er meint? Wir sind keine Hellseher. – Olaf
@Olaf Warum nicht zwol fragen? Denn wie ich ihn zitierte, hat er schon gesagt, dass er nicht in Kommentaren darüber reden wollte. Was ist mit einem minimalen, vollständigen und verifizierbaren Beispiel? Nun, ich stelle diese Frage genau, weil ich vermeiden will, in eine mir unbekannte Fallgrube zu fallen, die es notwendig machen würde, solch ein minimales, vollständiges und überprüfbares Beispiel zu schaffen. Wenn es um UB in C geht, denke ich, dass der Satz "besser verhindern als heilen" vollständig gilt. – gaazkam
Ich bin nicht sicher, dass Sie alles tun können, ohne die ganze Reihe von Schnittstellen, die sockaddr beinhalten, zu überarbeiten. Was auch immer Sie tun bestehende Funktion immer noch erwarten struct sockaddr * und nicht irgendeine Art von Union. –