2015-06-26 25 views
8

Ist es OK, ein Double-Array auf eine Struktur aus Doppel zu werfen?Casting Doppel-Array zu einer Struktur von Doppel

struct A 
{ 
    double x; 
    double y; 
    double z; 
}; 

int main (int argc , char ** argv) 
{ 
    double arr[3] = {1.0,2.0,3.0}; 
    A* a = static_cast<A*>(static_cast<void*>(arr)); 
    std::cout << a->x << " " << a->y << " " << a->z << "\n"; 
} 

Diese Drucke 1 2 3. Aber ist es garantiert immer mit jedem Compiler zu arbeiten?

EDIT: Nach

9.2.21: Ein Zeiger zu einem Objekt struct Standard-Layouts, in geeigneter Weise umgewandelt? Mit einem reinterpret_cast zeigt er auf seinen ursprünglichen Member (...) und umgekehrt.

wenn ich meinen Code mit

struct A 
{ 
    double & x() { return data[0]; } 
    double & y() { return data[1]; } 
    double & z() { return data[2]; } 
private: 
    double data[3]; 
}; 

int main (int, char **) 
{ 
    double arr[3] = {1.0,2.0,3.0}; 
    A* a = reinterpret_cast<A*>(arr); 
    std::cout << a->x() << " " << a->y() << " " << a->z() << "\n"; 
} 

ersetzen dann ist es garantiert zu arbeiten. Richtig? Ich verstehe, dass viele Leute das nicht ästhetisch ansprechend finden würden, aber es gibt Vorteile beim Arbeiten mit einer Struktur und nicht beim Kopieren der Eingangsarraydaten. Ich kann Memberfunktionen in dieser Struktur definieren, um Skalar- und Vektorprodukte, Entfernungen usw. zu berechnen, was meinen Code viel leichter verständlich macht, als wenn ich mit Arrays arbeiten würde.

Wie sei es

int main (int, char **) 
{ 
    double arr[6] = {1.0,2.0,3.0,4.0,5.0,6.0}; 
    A* a = reinterpret_cast<A*>(arr); 
    std::cout << a[0].x() << " " << a[0].y() << " " << a[0].z() << "\n"; 
    std::cout << a[1].x() << " " << a[1].y() << " " << a[1].z() << "\n"; 
} 

Ist dies garantiert auch arbeiten oder die Compiler etwas nach den Datenelementen, so dass sizeof(A) > 3*sizeof(double) setzen könnten? Und gibt es irgendeinen portablen Weg, den Compiler daran zu hindern?

+0

Jeder kann einen Compiler schreiben, das ist also eine schwierige Frage. Warum geben Sie nicht die Compiler an, die Sie verwenden werden? Meine Vermutung ist, dass alle großen Compiler dasselbe handhaben und es funktioniert. –

+0

Höchstwahrscheinlich nicht (wenn Sie nicht nur double verwenden möchten), aufgrund von [Datenstrukturausrichtung] (https://en.wikipedia.org/wiki/Data_structure_alignment) –

+0

Sie brechen die strenge Aliasing-Regel. – Jarod42

Antwort

8

Nein, das ist nicht garantiert.

Das einzige, was von jedem Compiler Einsetzen padding zwischen x und y verbietet, oder zwischen y und z ist gesunder Menschenverstand. Es gibt keine Regel in irgendeinem Sprachstandard, die es verbieten würde.

Auch wenn kein Padding vorhanden ist, auch wenn die Darstellung von A exakt mit der von double[3] übereinstimmt, ist es immer noch nicht gültig. Die Sprache erlaubt es Ihnen nicht vorzugeben, dass ein Typ wirklich ein anderer Typ ist. Sie dürfen nicht einmal eine Instanz von struct A { int i; }; behandeln, als wäre es eine struct B { int i; };.

1

Von allem, was ich weiß, ist die Antwort: ja.

Die einzige Sache, die Sie wegwerfen könnte, ist eine # Pragma-Direktive mit einigen sehr ungewöhnlichen Ausrichtung Einstellung für die Struktur. Wenn zum Beispiel ein Double 8 Bytes auf Ihrem Rechner benötigt und die #pragma-Anweisung sagt, dass jedes Member an 16-Byte-Grenzen ausgerichtet werden soll, die Probleme verursachen könnten. Ansonsten geht es dir gut.

1

Nein ist es nicht garantiert, auch wenn es mit allen Compilern funktionieren sollte ich über gemeinsame Architekturen kennen, weil C-Sprachspezifikation sagt:

6.2.6 Darstellungen von Arten 6.2.6.1 Allgemeines1 Die Darstellungen aller Typen sind nicht spezifiziert, außer wie in diesem Abschnitt angegeben. Und es sagt nichts über die Standardauffüllung in einer Struktur.

Natürlich verwenden übliche Architekturen höchstens 64Bits, was der Größe eines Double auf dieser Architektur entspricht, also sollte es keine Auffüllung geben und Ihre Konvertierung sollte funktionieren.

Aber Vorsicht: Sie explizit nicht definiertes Verhalten berufen sich, und der nächsten Generation von Compilern tun könnte etwas, wenn eine solche Besetzung zusammenzustellen.

-2

Ich stimme hier nicht überein. Eine Struktur mit drei Doubles ist genau dasselbe wie ein Array mit 3 Doubles. Es sei denn, Sie packen die Struktur speziell anders und befinden sich auf einem seltsamen Prozessor, der eine ungerade Anzahl von Bytes für das Doppelte hat.

Es ist nicht in die Sprache integriert, aber ich würde mich dabei sicher fühlen. Stilistisch würde ich es nicht tun, weil es nur verwirrend ist.

2

Der Standard gibt wenig Garantien über das Speicherlayout von Objekten.

Für die Klassen/structs:

9.2./15: nicht-statische Datenelemente einer Klasse mit der gleichen Zugriffskontrolle zugeordnet sind, so dass später Mitglieder höher haben Adressen innerhalb eines Klasse-Objekts. Die Reihenfolge der Zuweisung von nicht statischen Daten Mitglieder mit unterschiedlicher Zugriffskontrolle ist nicht spezifiziert. Implementierung Ausrichtung Anforderungen möglicherweise zwei benachbarte Mitglieder nicht sofort hintereinander zugeordnet werden; Anforderungen für Platz für die Verwaltung virtueller Funktionen und virtueller Basisklassen.

Bei Arrays sind die Elemente zusammenhängend. Es ist nichts über die Ausrichtung gesagt hat, so kann oder auch nicht gleiche Ausrichtungsregeln verwenden, als in struct:

8.3.4: Ein Gegenstand des Array-Typs enthält einen aneinander angrenzend zugeordnet nicht leeren Satz von N Subobjekte des Typs T.

Das einzige, was Sie sicher in Ihrem speziellen Beispiel sein kann, ist, dass a.x-arr[0] entspricht, wenn ein reinterpret_cast mit:

9.2.21: Ein Zeiger auf ein Standard-Layout-Strukturobjekt, das mit einem reinterpret_cast entsprechend konvertiert wurde, zeigt auf seinen ursprünglichen Member (...) und umgekehrt. [
>