Frage

Ich versuche, zwei Warnungen zu beheben, wenn ich ein bestimmtes Programm mit GCC erstellt habe. Die Warnungen sind:

WARNUNG: Derferencing typbeckener Zeiger brechen strenge Aliasing-Regeln [-wstrict-Aliasing

Und die beiden Schuldigen sind:

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));

und

*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset);

Incoming_buf und Ausgangsströmung_buf werden wie folgt definiert:

char                    incoming_buf[LIBIRC_DCC_BUFFER_SIZE];

char                    outgoing_buf[LIBIRC_DCC_BUFFER_SIZE];

Dies scheint subtil anders zu sein als die anderen Beispiele für diese Warnung, die ich untersuchte. Ich würde es vorziehen, das Problem zu beheben, anstatt strenge Aliasing-Checks zu deaktivieren.

Es gab viele Vorschläge, eine Gewerkschaft zu verwenden - was könnte eine geeignete Gewerkschaft für diesen Fall sein?

War es hilfreich?

Lösung

Lassen Sie uns zunächst untersuchen, warum Sie die Aliasing -Verstoßwarnungen erhalten.

Aliasing -Regeln Sagen Sie einfach, dass Sie nur über seinen eigenen Typ, seinen signierten / unsignierten Variantenstyp oder über einen Zeichentyp auf ein Objekt zugreifen können (über einen eigenen Typ (signiert / unsigniert).char, signed char, unsigned char).

C sagt, dass Verstoß gegen Aliasing -Regeln ein undefiniertes Verhalten hervorruft (Also nicht!).

In dieser Linie Ihres Programms:

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));

Obwohl die Elemente der incoming_buf Array sind vom Typ char, Sie greifen auf sie zu als auf sie zu unsigned int. In der Tat das Ergebnis des Dereferenzoperators im Ausdruck *((unsigned int*)dcc->incoming_buf) ist von unsigned int Typ.

Dies ist ein Verstoß gegen die Aliasing -Regeln, da Sie nur das Recht haben, auf Elemente von zuzugreifen incoming_buf Array durch (siehe Regeln Zusammenfassung oben!) char, signed char oder unsigned char.

Beachten Sie, dass Sie in Ihrem zweiten Schuldigen genau das gleiche Aliasing -Problem haben:

*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset);

Sie greifen auf die zu char Elemente von outgoing_buf durch unsigned int, Es ist also ein Aliasing -Verstoß.

Vorgeschlagene Lösung

Um Ihr Problem zu beheben, können Sie versuchen, die Elemente Ihrer Arrays direkt in dem Typ zu definieren, auf den Sie zugreifen möchten:

unsigned int incoming_buf[LIBIRC_DCC_BUFFER_SIZE / sizeof (unsigned int)];
unsigned int outgoing_buf[LIBIRC_DCC_BUFFER_SIZE / sizeof (unsigned int)];

(Übrigens die Breite von unsigned int wird die Implementierung definiert, daher sollten Sie in Betracht ziehen, die Verwendung zu verwenden uint32_t Wenn Ihr Programm annimmt unsigned int ist 32-Bit).

Auf diese Weise könnten Sie speichern unsigned int Objekte in Ihrem Array, ohne gegen die Aliasing -Regeln zu verstoßen, indem Sie über den Typ auf das Element zugreifen char, so was:

*((char *) outgoing_buf) =  expr_of_type_char;

oder

char_lvalue = *((char *) incoming_buf);

BEARBEITEN:

Ich habe meine Antwort vollständig überarbeitet, insbesondere ich erkläre, warum das Programm die Aliasing -Warnungen vom Compiler erhält.

Andere Tipps

Um das Problem zu lösen, Nicht Wortspiel und Alias! Die einzige "korrekte" Möglichkeit, einen Typ zu lesen T soll einen Typ zuweisen T und füllen Sie seine Darstellung bei Bedarf ein:

uint32_t n;
memcpy(&n, dcc->incoming_buf, 4);

Kurz gesagt: Wenn Sie eine Ganzzahl wünschen, müssen Sie eine Ganzzahl machen. Es gibt keine Möglichkeit, das auf sprachbezogene Weise umzugehen.

Die einzige Zeigerkonvertierung, die Sie zugelassen haben (für die Zwecke von E/A im Allgemeinen), besteht darin, die Adresse von zu behandeln eine vorhandene Variable vom Typ T Als ein char*, oder besser gesagt als Zeiger auf das erste Element einer Reihe von Zeichen der Größe sizeof(T).

union
{
    const unsigned int * int_val_p;
    const char* buf;
} xyz;

xyz.buf = dcc->incoming_buf;
unsigned int received_size = ntohl(*(xyz.int_val_p));

Vereinfachte Erläuterung 1. C ++ Standard gibt an, dass Sie versuchen sollten, Daten selbst auszurichten. G ++ ist eine Extrameile, um Warnungen zu diesem Thema zu generieren. 2. Sie sollten es nur versuchen, wenn Sie die Datenausrichtung Ihrer Architektur/Ihr System und in Ihrem Code vollständig verstehen (z. B. ist der obige Code auf Intel 32/64; Ausrichtung 1; Win/Linux/BSD/Mac) 3. Der einzige praktische Grund, den obigen Code zu verwenden, besteht darin, Compiler -Warnungen zu vermeiden, wann und wenn Sie wissen, was Sie tun

Wenn ich für diesen Fall, für diesen Fall, ist das Problem das Design der APIs NTOHL und HTONL sowie verwandte Funktions -APIs. Sie hätten nicht als numerisches Argument mit numerischer Rückkehr geschrieben werden dürfen. (Und ja, ich verstehe den Makrooptimierungspunkt) Sie hätten als "n" -Seite als Zeiger auf einen Puffer konzipiert werden sollen. Wenn dies erledigt ist, verschwindet das ganze Problem und die Routine ist genau, welcher Endian der Host ist. Zum Beispiel (ohne Versuch zu optimieren):

inline void safe_htonl(unsigned char *netside, unsigned long value) {
    netside[3] = value & 0xFF;
    netside[2] = (value >> 8) & 0xFF;
    netside[1] = (value >> 16) & 0xFF;
    netside[0] = (value >> 24) & 0xFF;
};

Wenn Sie Gründe haben, die Sie nicht ermöglichen, die Art des Quellobjekts zu ändern (wie in meinem Fall), und Sie sind absolut zuversichtlich, dass der Code korrekt ist und das tut, was mit diesem Char -Array zu tun hat, um Warnungen zu vermeiden, die Sie kann Folgendes tun:

unsigned int* buf = (unsigned int*)dcc->incoming_buf;
unsigned int received_size = ntohl (*buf);

Zeiger auf nicht signiert und dann zurück zum Zeiger.

unsigned int empfangen_size = ntohl ( *((nicht signiert *) ((nicht signiert) dcc-> coming_buf)));

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top