Dies scheint sich subtil von den anderen Beispielen dieser Warnung zu unterscheiden, die ich untersucht habe. Ich würde es vorziehen, das Problem zu beheben, anstatt Strict-Aliasing-Prüfungen zu deaktivieren.
Es gab viele Vorschläge zur Verwendung einer Verbindung – welche Verbindung könnte für diesen Fall geeignet sein?
Interessant … Strict-Aliasing sollte nicht gelten char*. Oder übersehe ich etwas?
– Mystisch
11. Januar 2012 um 18:30 Uhr
@Mystcial Ja, was Sie vermissen, ist, dass es bei einem Objekt des Typs keine Aliasing-Verletzung gibt T1 wird mit einem lvalue vom Typ zugegriffen T2 und T2 ist charaber wenn T1 ist char und T2 ist keine signierte/unsignierte Variante von charliegt eine Aliasing-Verletzung vor.
– au
11. Januar 2012 um 19:08 Uhr
@Mystical: Du hast es falsch herum verstanden!
– Kerrek SB
11. Januar 2012 um 19:14 Uhr
ouah
Lassen Sie uns zunächst untersuchen, warum Sie die Aliasing-Verletzungswarnungen erhalten.
Aliasing-Regeln Sagen Sie einfach, dass Sie auf ein Objekt nur über seinen eigenen Typ, seinen signierten/unsignierten Variantentyp oder über einen Zeichentyp (char, signed char, unsigned char).
C sagt, dass das Verletzen von Aliasing-Regeln undefiniertes Verhalten hervorruft (also nicht!).
In dieser Zeile Ihres Programms:
unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));
obwohl die Elemente der incoming_buf array sind vom Typ chargreifen Sie darauf zu als unsigned int. Tatsächlich das Ergebnis des Dereferenzierungsoperators 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 Regelzusammenfassung oben!) char, signed char oder unsigned char.
Beachten Sie, dass Sie bei Ihrem zweiten Täter genau das gleiche Aliasing-Problem haben:
Sie greifen auf die zu char Elemente von outgoing_buf durch unsigned intes handelt sich also um eine Aliasing-Verletzung.
Vorgeschlagene Lösung
Um Ihr Problem zu beheben, könnten 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 ist die Implementierung definiert, daher sollten Sie die Verwendung von in Betracht ziehen uint32_t wenn Ihr Programm davon ausgeht unsigned int ist 32-Bit).
Auf diese Weise könnten Sie speichern unsigned int Objekte in Ihrem Array, ohne die Aliasing-Regeln zu verletzen, indem Sie über den Typ auf das Element zugreifen charso was:
*((char *) outgoing_buf) = expr_of_type_char;
oder
char_lvalue = *((char *) incoming_buf);
BEARBEITEN:
Ich habe meine Antwort komplett überarbeitet, insbesondere erkläre ich, warum das Programm die Aliasing-Warnungen vom Compiler erhält.
Die Warnung kann durch doppeltes Durchwerfen zum Schweigen gebracht werden void *. siehe meine antwort
– yanychar
17. Mai um 16:46 Uhr
Um das Problem zu lösen, kein Wortspiel und Alias! Die einzig “richtige” Art, einen Typ zu lesen T ist die Zuordnung eines Typs T und füllen Sie seine Darstellung bei Bedarf aus:
uint32_t n;
memcpy(&n, dcc->incoming_buf, 4);
Kurz gesagt: Wenn Sie eine ganze Zahl wollen, müssen Sie eine ganze Zahl machen. Es gibt keine Möglichkeit, das sprachlich geduldet zu umgehen.
Die einzige Zeigerkonvertierung, die Ihnen erlaubt ist (im Allgemeinen für E/A-Zwecke), besteht darin, die Adresse von zu behandeln eine vorhandene Variable des Typs T Als ein char*oder besser gesagt, als Zeiger auf das erste Element eines Arrays von Zeichen der Größe sizeof(T).
Ich bin mir nicht sicher sizeof(uint32_t) ist garantiert 4, daher müssen Sie möglicherweise Ihre anpassen memcpy
– OmarL
24. August 2020 um 15:27 Uhr
@OmarL: richtig. uint32_t hat garantiert genau 32 Wertbits und keine Füllbits, aber sizeof(uint32_t) kann sein 2 wenn unsigned char hat 16 Bit und sogar 1 wenn unsigned char hat 32 Bit. Das Beispiel sollte wie folgt geändert werden memcpy(&n, dcc->incoming_buf, sizeof(n));
– chqrlie
17. Mai um 17:19 Uhr
Echter Name
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 Erklärung 1. Der c++-Standard besagt, dass Sie versuchen sollten, Daten selbst auszurichten, g++ geht noch einen Schritt weiter, um Warnungen zu diesem Thema zu generieren. 2. Sie sollten es nur versuchen, wenn Sie die Datenausrichtung auf Ihrer Architektur/Ihrem System und in Ihrem Code vollständig verstehen (zum Beispiel ist der obige Code eine sichere Sache 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, WENN und WENN Sie wissen, was Sie tun
Henri Socha
Wenn ich darf, ist das Problem meiner Meinung nach in diesem Fall das Design der ntohl- und htonl- und verwandten Funktions-APIs. Sie sollten nicht als numerisches Argument mit numerischer Rückgabe geschrieben werden. (und ja, ich verstehe den Punkt der Makrooptimierung) Sie sollten so konzipiert sein, dass die ‘n’-Seite ein Zeiger auf einen Puffer ist. Wenn dies erledigt ist, verschwindet das ganze Problem und die Routine ist genau, egal welches Endian der Host ist. Zum Beispiel (ohne Optimierungsversuch):
Wenn Sie Gründe haben, die es Ihnen nicht erlauben, den Typ des Quellobjekts zu ändern (wie es in meinem Fall war), und Sie absolut sicher sind, dass der Code korrekt ist und das tut, was mit diesem Zeichenarray beabsichtigt ist, vermeiden Sie Warnungen kann Folgendes tun:
Warnungen wegzuwerfen ist schlecht. Dieser Code tut nichts gegen striktes Aliasing und kann auch Ausrichtungsbeschränkungen verletzen.
– Andreas Henle
20. April 2021 um 14:42 Uhr
DosMan
Ich habe kürzlich ein Projekt von GCC 6 auf GCC 9 aktualisiert und diese Warnung wurde angezeigt. Das Projekt befindet sich auf einem 32-Bit-Mikrocontroller, und ich hatte eine Struktur erstellt, um auf die einzelnen Bytes eines 32-Bit-Maschinenregisters zuzugreifen:
was die Warnung im neuen Compiler erzeugte. Ich fand heraus, dass ich die Warnung beseitigen konnte, indem ich meine Struktur in einer Vereinigung mit dem ursprünglichen Typ kombinierte:
wo TCC_WEXCTRL_Type ist die Art der WEXCTRL wie in den Header-Dateien des Herstellers angegeben.
Ich bin mir nicht sicher, ob dies als vollständig konformer Fix angesehen wird oder ob GCC es einfach nicht erkennt. Wenn dies nicht funktioniert hätte (oder in einem anderen GCC-Upgrade hängen geblieben wäre), würde ich dazu übergehen, eine Vereinigung der Zeigertypen zu verwenden, wie in diesem Thread von Real Name beschrieben.
Warnungen wegzuwerfen ist schlecht. Dieser Code tut nichts gegen striktes Aliasing und kann auch Ausrichtungsbeschränkungen verletzen.
– Andreas Henle
20. April 2021 um 14:42 Uhr
Jewgeni Jaschin
C Cast hat nicht funktioniert, aber reinterpret_cast<> hat mir in einer ähnlichen Situation geholfen.
14037700cookie-checkFix für die Dereferenzierung von typgesponnenen Zeigern unterbricht Strict-Aliasingyes
Interessant … Strict-Aliasing sollte nicht gelten
char*
. Oder übersehe ich etwas?– Mystisch
11. Januar 2012 um 18:30 Uhr
@Mystcial Ja, was Sie vermissen, ist, dass es bei einem Objekt des Typs keine Aliasing-Verletzung gibt
T1
wird mit einem lvalue vom Typ zugegriffenT2
undT2
istchar
aber wennT1
istchar
undT2
ist keine signierte/unsignierte Variante vonchar
liegt eine Aliasing-Verletzung vor.– au
11. Januar 2012 um 19:08 Uhr
@Mystical: Du hast es falsch herum verstanden!
– Kerrek SB
11. Januar 2012 um 19:14 Uhr