2016-04-13 4 views
0

Nachdem ich gerade Ausrichtungsprobleme zum ersten Mal entdeckt habe, bin ich mir nicht sicher, welche Methode der beste/sicherste Weg ist, mit ihnen umzugehen. Ich habe einen Datensatz, den ich serialisiere, um ihn über einen Stream zu senden, und umgekehrt, so dass er die Schnittstellenspezifikation erfüllen muss und kein Padding enthalten muss.Ada Pragma Pack oder Alignment-Attribut für Datensätze?

das Beispiel Datensatz Gegeben:

type MyRecord is record 
a : Unsigned_8; 
b : Unsigned_32; 
end record; 

Diese standardmäßig würde 8 Bytes erfordern, aber ich bin in der Lage zwei Methoden Verpackung zu entfernen, mit:

for MyRecord'Alignment use 1; 

oder

pragma Pack (MyRecord); 

I Ich habe ein paar Fragen zu C-Beispielen gefunden, konnte aber keine eindeutige Antwort darauf finden, welche Methode es ist die am besten geeignete, wie zu bestimmen, welche Methode zu verwenden oder ob sie gleichwertig sind?

UPDATE

Als ich versuchte, beide auf meinem ‚echten‘ Code eher als ein einfaches Beispiel, das ich, dass die Ausrichtung gefunden Attribut erreicht, was ich suchte. pragma Pack hat die Größe erheblich reduziert, nicht bestätigt, aber ich nehme an, dass es die vielen aufgezählten Typen, die ich verwende, gepackt hat, wobei das Attribut 'Size use 8' für jeden Typ außer Kraft gesetzt wurde.

Antwort

4

Für Streams Sie MyRecord ohne Darstellung Klauseln und verwenden Sie den Standard MyRecord’Write und MyRecord’Read verlassen konnte; ARM 13.13.2(9) sagt

Für Elementartypen, Read liest (und schreiben schreibt) die Anzahl der Strom durch die Stream_Size implizierten Elemente für den Typ T; Die Darstellung dieser Stream-Elemente ist implementiert. Für zusammengesetzte Typen wird das Attribut Write oder Read für jede Komponente in kanonischer Reihenfolge aufgerufen, wobei sich die letzte Dimension für ein Array am schnellsten ändert (es sei denn, die Konvention des Arrays ist Fortran, wobei sich die erste Dimension am schnellsten ändert) und positional Aggregatauftrag für einen Datensatz

Ein möglicher Nachteil der GNAT Implementierung (und vielleicht auch andere) ist, dass die ’Write und ’Read Anrufe jedes Ende in einem Aufruf an die zugrunde liegende Netzwerk-Software. Kein Problem (abgesehen von möglicher Ineffizienz) normalerweise, aber wenn Sie TCP_NODELAY (oder schlechter, UDP) verwenden, ist dies nicht das Verhalten, das Sie suchen.

Überladen ’Write führt zurück zu Ihrem ursprünglichen Problem (aber zumindest ist es auf die Überladung beschränkt, so dass der Rest Ihres Programms mit richtig ausgerichteten Daten umgehen kann).

Ich habe dafür einen In-Memory-Stream verwendet (besonders den UDP-Fall); ’Write an den In-Memory-Stream, dann senden Sie die Stream_Element_Array an den Sockel.Ein Beispiel ist ColdFrame.Memory_Streams (, .adb).

+0

+1. Packen sollte verwendet werden, um die In-Memory-Repräsentation zu steuern, nicht die Stream-Repräsentation. Wenn Sie ein bestimmtes Format "on the wire" benötigen (weil das andere Ende dieses Format erwartet), können Sie die Standardprozeduren überladen, um dieses Format unabhängig von der Packung im Speicher zu erzeugen. –

+0

Wenn ich dies tue, sendet es ein Feld pro Paket und nicht den gesamten serialisierten Datensatz pro Paket? – MattP

+0

Siehe aktualisierte Antwort. –

1

Ich denke, dass Sie die Aufzeichnung Darstellung Klauseln wollen, wenn Sie die volle Kontrolle wollen:

for MyRecord'Size use 40; 
for MyRecord use record 
    a at 0 range 0 .. 7; 
    b at 1 range 0 .. 31; 
end record; 

(oder so, vielleicht habe ich hier einige der Indizes verkorkste).

NB: bearbeitet wie pro Kommentar von Simon

+1

'b bei 1 Bereich 0 .. 31' Ich denke! –

+0

Ist die Darstellungsklausel relevant für das Schreiben in einen Stream? (Zu faul, um es jetzt zu suchen.) –

+0

@JacobSparreAndersen: Für einen Stream würde ich mein eigenes Lese- und Schreibprogramm definieren, um das Kabelformat zu definieren, unabhängig davon, wie der Compiler den Datensatz im Speicher packt. –