2012-04-03 17 views
5

Ich habe eine Struktur, die zum Speichern von benutzerdefinierten Daten (d. H. Von einem Plugin) zielt. Es hat eine solche char[] mit einer gegebenen maximalen Größe, um diese Daten zu speichern.Typ punning, char [] und Dereferenzierung

struct A 
{ 
    // other members omitted 
    // data meant to be type punned, only contains PODs 
    char data[256]; 
}; 

dann gibt es eine Probe Benutzerstruktur, die eine statische Funktion hat, sich zu werfen von A.

struct B 
{ 
    int i; 
    double d; 

    static B& FromA_ref(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return * reinterpret_cast<B*>(a.data); 
    } 
}; 

ich kompilieren mit g++ -O3 -std=c++0x -Wall -o test test.cpp (GCC 4.6.1).

Dies löst eine dereferencing type-punned pointer will break strict-aliasing rules Warnung aus. Ich dachte, das wäre in Ordnung, da ich einen char[] als Speicher verwendet habe, von dem ich dachte, er würde denselben Regeln folgen wie char*. Ich finde es seltsam, dass es nicht so ist. Nicht wahr? Nun, ... ich kann es jetzt nicht ändern, also lass uns weitergehen.

Nun wollen wir die folgende Methode berücksichtigen:

struct B 
{ 
    .... 
    static B* FromA_ptr(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return reinterpret_cast<B*>(a.data); 
    } 
} 

Da ich nichts bin dereferencing hier GCC nicht ausgibt jede Warnung. Auch nicht, wenn ich meinen Zeiger später auf B verwende.

A a; 
auto b = B::FromA_ptr(a); 
b->i = 2; // no warnings. 

Aber ist es sicher, so zu tun? Ich habe das Gefühl, dass ich mich eher mit dem Problem herumgearbeitet habe, als es zu lösen. Bei mir -> wird die Variable immer noch dereferenziert.

Oder gibt es einen besseren Weg, um den Effekt zu erzielen? I.E. eine änderbare Referenz (oder einen Zeiger) erhalten, die von einem Speicher in einer anderen Struktur stammt? (Union funktioniert nicht, da der Satz der gespeicherten Typen nicht bekannt ist, wenn A definiert ist und einige über Plug-Ins hinzugefügt werden können, memcpy wird mich zwingen, die Daten hin und her zu kopieren, obwohl es der einzige sichere Weg zu sein scheint far)

+0

Ich bin kein Experte, aber suchen Sie nach dem Attribut "__may_alias__"? http://blog.worldofcoding.com/2010/02/solving-gcc-44-strict-aliasing-problems.html –

+0

Wie auch immer, wie gehen Sie mit dem Ausrichtungsproblem um? – curiousguy

+0

@curiousguy: bisher nicht, aber ich sollte. Auf x86 vermute ich, dass ich die Leistung im schlimmsten Fall verschlechtern kann. Ich hoffe "__attribute __ ((aligned (8)));" wäre genug, da ich nicht versuche, irgendetwas automatisch zu vektorisieren. Wahrscheinlich sagt 'may_alias' GCC bereits, dass es auf die Ausrichtung achten soll, bevor es zu viel seltsames Zeug macht. –

Antwort

3

Die Antwort ist nein, es ist nicht sicher (siehe dieser SO question)

GCC davon ausgehen, dass die Zeiger können nicht alias. Zum Beispiel, wenn Sie durch eins zuweisen, dann lesen Sie von dem anderen, GCC kann, als eine Optimierung, das Lesen und Schreiben neu ordnen - ich habe gesehen, dass dies im Produktionscode passiert, es ist nicht angenehm zu debuggen.

Attribut ((may_alias)) auf den Typen verwendet wird, ist wahrscheinlich die nächst Sie deaktivieren die Annahme für einen bestimmten Abschnitt des Codes erhalten können.

Verwandte Themen