Ausrichtung entlang der 4-byte-Grenzen
Hab ich neulich nachdenken über die Ausrichtung... Es ist etwas, dass wir normalerweise nicht denken müssen, aber ich habe erkannt, dass einige Prozessoren erfordern Objekte werden ausgerichtet auf 4-byte-Grenzen. Was genau bedeutet das, und welche spezifischen Systeme alignment-Anforderungen?
Angenommen ich habe ein beliebiger Zeiger:
unsigned char* ptr
Nun, ich bin versucht zu rufen Sie einen double-Wert aus einem Speicherbereich:
double d = **((double*)ptr);
Wird das Probleme verursachen?
Beachten Sie, dass Doppelzimmer sehr gut haben können sizeof(double) Ausrichtung, die wiederum einen > 4. Und Typen mit sizeof(T)<4 nie Ausrichtungen auf 4-byte-Grenzen - anders konnte man Sie nicht, richten Sie beide Elemente von T[2] !
Ich versuche mir vorzustellen, welche Art von Programm-design brauchen würden, um Sie zu Lesen, verdoppelt sich von unaligned beliebigen Zeiger. Ich kann nicht glauben, eine praktische Szenario-zumindest für ein Szenario, es gibt bessere Lösungen, die nicht mit Problemen Ausrichtung und sind eher für die cross-Plattform-Codierung.
Solange ptr-Punkte auf dynamisch allokierten Speicher, es wird funktionieren. Wenn ptr Punkte bei einem statischen array (globalen oder lokalen), dann gibt es keine Garantien. (siehe meine Antwort weiter unten für details)
Können wir die Zeiger der Ausrichtung auf eine 4-byte-Grenze in einer effizienten Art und Weise ?
Die Sache zu beachten hier ist, dass einige ISAs (z.B. x86) erlauben es Ihnen, laden, Speicher in einem 32-bit-register mit einer Adresse, die nicht 32-bit-ausgerichtet mit einem normalen load-Anweisung. Die meisten RISC ISAs nicht, und verlangen, dass der compiler emittieren zusätzliche Anweisungen, um 2 Lasten plus einige bit-twiddling für alle Daten, die beiderseits der Grenze. Es werden in der Regel nicht gut (best-case) auf jeder Art von Architektur, vorausgesetzt, der compiler erkennt die situation. Wenn der compiler nichts von den unaligned access (worst-case), dann wird es funktionieren auf x86, andere aber nicht.
Ich versuche mir vorzustellen, welche Art von Programm-design brauchen würden, um Sie zu Lesen, verdoppelt sich von unaligned beliebigen Zeiger. Ich kann nicht glauben, eine praktische Szenario-zumindest für ein Szenario, es gibt bessere Lösungen, die nicht mit Problemen Ausrichtung und sind eher für die cross-Plattform-Codierung.
Solange ptr-Punkte auf dynamisch allokierten Speicher, es wird funktionieren. Wenn ptr Punkte bei einem statischen array (globalen oder lokalen), dann gibt es keine Garantien. (siehe meine Antwort weiter unten für details)
Können wir die Zeiger der Ausrichtung auf eine 4-byte-Grenze in einer effizienten Art und Weise ?
Die Sache zu beachten hier ist, dass einige ISAs (z.B. x86) erlauben es Ihnen, laden, Speicher in einem 32-bit-register mit einer Adresse, die nicht 32-bit-ausgerichtet mit einem normalen load-Anweisung. Die meisten RISC ISAs nicht, und verlangen, dass der compiler emittieren zusätzliche Anweisungen, um 2 Lasten plus einige bit-twiddling für alle Daten, die beiderseits der Grenze. Es werden in der Regel nicht gut (best-case) auf jeder Art von Architektur, vorausgesetzt, der compiler erkennt die situation. Wenn der compiler nichts von den unaligned access (worst-case), dann wird es funktionieren auf x86, andere aber nicht.
InformationsquelleAutor Tony the Pony | 2009-08-06
Du musst angemeldet sein, um einen Kommentar abzugeben.
Kann es auf jeden Fall zu Problemen auf einigen Systemen.
Beispielsweise auf ARM-basierte Systeme, können Sie nicht die Adresse eine 32-bit-Wort, dass ist nicht ausgerichtet auf eine 4-byte-Grenze. Dies führt zu eine Zugriffsverletzung Ausnahme. Auf x86-Sie können Zugang zu solchen nicht-ausgerichtete Daten, wenn die performance etwas leidet, da die beiden Wörter müssen aus dem Speicher geholt, anstatt nur einer.
Es definitiely ist ein problem auf den ARM, wenn beliebige byte-Positionen verwendet werden, wie laalto und starblue Punkt, aus. Aber Speicherblöcke zugewiesen wird, immer eine ausreichende (D. H. 16 byte) Ausrichtung, auch wenn Sie verwendet werden für Zeichen-arrays. Auch aufpassen, für MSB/LSB beim überqueren Plattformen mit dieser Technik.
Offenbar ARM-v6 (in der Regel) und oben (immer) definieren unaligned Zugriffe zu sagen, zu tun, die x86 / x64, was nun, außer für LDM / STM und vielleicht auch anderen nicht-"Bemerkenswerte" Ausnahmen.
InformationsquelleAutor laalto
Hier ist, was die Intel x86/x64-Referenz-Handbuch sagt über Ausrichtungen:
Vergessen Sie nicht, die Referenz-Handbücher sind die ultimative Quelle der information der verantwortliche Entwickler und Ingenieur, also, wenn Sie ' re Umgang mit etwas, das gut dokumentiert, wie Intel CPUs, nur nachschlagen, was das Referenz-Handbuch sagt zu dem Problem.
stimmt, aber andere Architekturen haben Ihre eigenen Referenz-Handbücher als gut.
Ja, ich meine nur, dass man manchmal code schreiben möchten, die nicht für eine bestimmte Architektur (in der Tat,, die passiert wurden, der übliche Fall bei mir so weit). In dieser situation, CPU-Referenz-Handbücher helfen nicht, Sie können nur verlassen sich auf den C++ - standard.
InformationsquelleAutor Tamas Czinege
Ja, das kann eine Reihe von Problemen verursachen. Der C++ - standard nicht wirklich garantieren, dass es funktioniert. Man kann nicht einfach willkürlich cast zwischen Zeiger-Typen.
Wenn Sie werfen einen char-Zeiger auf ein double-Zeiger, verwendet es eine
reinterpret_cast
gilt eine Implementierung-definiert mapping. Sie sind nicht garantiert, dass der resultierende Zeiger enthalten die gleiche bit-Muster, oder, dass es auf die gleiche Adresse verweisen, oder, naja, alles andere. In der Praxis, Sie sind auch nicht garantiert, dass der Wert, den Sie gerade Lesen, ist richtig ausgerichtet. Wenn die Daten wurde geschrieben, als eine Reihe von chars, dann verwenden Sie char ' s alignment-Anforderungen.Als für das, was Ausrichtung bedeutet im wesentlichen nur, dass die Startadresse der Wert sollte teilbar sein durch die Ausrichtung Größe. Adresse 16 ausgerichtet ist auf 1, 2, 4, 8 und 16-byte-Grenzen, zum Beispiel, also auf typische CPU ist, die Werte dieser Größen können hier gespeichert werden.
Adresse 6 ist nicht ausgerichtet auf eine 4-byte-Grenze, also sollten wir nicht speichern 4-byte-Werte gibt.
Es ist erwähnenswert, dass auch auf CPU ' s, die nicht durchzusetzen oder Ausrichtung erfordern Sie in der Regel immer noch eine deutliche Verlangsamung Zugriff auf nicht ausgerichtete Werte.
InformationsquelleAutor jalf
Ausrichtung wirkt sich auf das layout von Strukturen. Betrachten Sie dieses struct:
Auf einem 32-bit-CPU das layout dieser struct wird oft sein:
Voraussetzung ist, dass ein 32-bit-Wert muss ausgerichtet werden auf eine 32-bit-Grenze. Wenn die Struktur geändert wird, wie diese:
das layout wird so sein:
Den 16-bit-Wert, der ausgerichtet ist auf ein 16-bit-Grenze.
Manchmal möchte man pack die Strukturen vielleicht, wenn Sie wollen, passen die Struktur, die mit einem Daten-format. Durch die Verwendung einer compiler-option oder vielleicht ein
#pragma
Sie sind in der Lage, um den überschuss zu entfernen Raum:Jedoch der Zugriff auf eine nicht ausgerichtete Mitglied in einem struct verpackt, wird oft viel langsamer auf modernen CPU ' s, oder kann sogar zu einer Ausnahme führen.
InformationsquelleAutor Martin Liversage
Ja, das könnte zu Problemen führen.
4-Ausrichtung bedeutet einfach, dass der Zeiger, wenn man berücksichtigt, dass eine numerische Adresse, die ein Vielfaches von 4 ist. Wenn sich der Zeiger nicht ein Vielfaches der erforderlichen Ausrichtung, dann ist es nicht ausgerichtet. Es gibt zwei Gründe, warum der Compiler Ort alignment-Beschränkungen bei bestimmten Arten:
Wenn Sie in Fall (1) und die Doppel-4-ausgerichtet, und Sie versuchen, Ihren code mit einem
char *
- pointer, die nicht 4-ausgerichtet sind, dann werden Sie wahrscheinlich bekommen ein hardware-Falle. Einige hardware nicht auffangen. Nur es lädt ein Unsinn, Wert und wird fortgesetzt. Doch der C++ standard nicht definiert, was passieren kann (Undefiniertes Verhalten), so kann dieser code könnte Ihr computer in Brand.Auf x86, du bist noch nie in Fall (1), da die standard-load-Anweisungen verarbeiten kann unaligned Pointer. Auf ARM, es gibt keine nichtlinearen Lasten, und wenn Sie versuchen, eine dann Ihr Programm abstürzt (wenn man Glück hat. Einige Arme still fail).
Kommen wir zurück zu deinem Beispiel, die Frage ist, warum Sie versuchen, diese mit einem
char *
dass nicht 4-ausgerichtet. Wenn Sie erfolgreich schrieb ein Doppel über einedouble *
sind, dann werden Sie in der Lage sein, es zu Lesen zurück. Also, wenn Sie hatte ursprünglich eine "richtige" Zeiger auf double, die Sie werfen, umchar *
und nun sind Sie Gießen zurück, Sie müssen nicht sorgen zu machen über die Ausrichtung.Aber Sie sagte willkürliche
char *
, so dass ich denke, dass ist nicht das, was Sie haben. Wenn Sie Lesen ein Stück von Daten aus einer Datei, die enthält eine serialisierte doppelklicken, dann wird Sie muss stellen Sie sicher, dass die alignment-Anforderungen für Ihre Plattform gegeben sind, um dies zu tun, Stimmen. Wenn Sie 8 Byte für ein double in eine Datei-format, dann kann man nicht nur Lesen oder übel in einen char* buffer, Aufrechnung und dann gegossen, umdouble *
.Der einfachste Weg, dies zu tun ist, um sicherzustellen, dass Sie die Datei Lesen Daten in eine geeignete Struktur. Sie sind auch durch die Tatsache geholfen, dass die Speicherzuweisungen sind immer ausgerichtet, um die maximale Ausrichtung Voraussetzung jeder Art Sie sind groß genug, um enthalten. Also, wenn man reserviert einen Puffer groß genug, um enthalten eine doppelte, dann der start der Puffer hat, was Ausrichtung erforderlich ist, durch doppelklicken. So können Sie Lesen Sie die 8 bytes, die die Doppel an den Anfang des Puffers, cast (oder verwenden Sie eine union) und Lesen Sie die Doppel.
Alternativ könnte man etwas wie das hier tun:
Dies ist garantiert gültig (vorausgesetzt, un_ptr wirklich Punkte, um die bytes eines gültigen doppelte Vertretung für Ihre Plattform), weil doppelt ist POD und damit kopiert werden kann, byte-by-byte. Es ist vielleicht nicht die Schnellste Lösung, wenn Sie haben eine Menge verdoppelt, um zu laden.
Wenn Sie beim Lesen aus einer Datei, es ist eigentlich ein bisschen mehr als das, wenn Sie besorgt sind über die Plattformen mit nicht-IEEE-double-Darstellungen, oder mit 9-bit-bytes, oder einige andere ungewöhnliche Eigenschaften, wo es vielleicht nicht Wert bits in der gespeicherten Repräsentation eines double. Aber Sie wollte eigentlich nicht Fragen über Dateien, ich habe gerade es als Beispiel, und in jedem Fall, diese Plattformen sind viel seltener als die Ausgabe, die Sie sich Fragen, über, die ist für zu verdoppeln, um eine Angleichung Voraussetzung.
Schließlich überhaupt nichts mit Ausrichtung zu tun, Sie haben auch strenge aliasing sorgen zu machen, wenn Sie das
char *
über einen cast von einem Zeiger die nicht-alias-kompatibel mitdouble *
. Aliasing ist gültig zwischenchar *
selbst und nichts anderes, obwohl.Betrachten Sie zum Beispiel
char *p = new char[100]; char *ptr = p + 1;
ptr ist jetzt nicht ausgerichtet, wenn doppelte ist 4-ausgerichtet. Casting ptr zudouble *
dann Lesen eine doppelte ist Undefiniertes Verhalten (auch wenn Sie festgelegt habenp[1]
durchp[sizeof(double)]
0).InformationsquelleAutor Steve Jessop
Auf dem x86 ist es immer laufen, der Kurs effizienter, wenn Sie ausgerichtet.
Aber wenn Sie das MULTITHREADING dann zu beobachten, für lese -, schreib-reißen. Mit einem 64-bit-Wert benötigen Sie eine x64-Maschine, um Ihnen atomic-Lesen-und-schreiben zwischen threads.
Wenn Sie sagen, Sie Lesen den Wert aus einem anderen thread, wenn Sie sagen, dass die Inkrementierung zwischen 0x00000000.FFFFFFFF und 0x00000001.00000000, dann ein anderer thread könnte in der Theorie Lesen sagen, entweder 0 oder 1FFFFFFFF, vor allem, WENN SAGEN, dass der Wert AUSDRUCK EINER CACHE-LINE-Grenze.
Ich empfehle Duffy ' s "Concurrent Programming on Windows" für seine nette Diskussion von Speicher-Modellen, auch nur zu erwähnen Ausrichtung Fallstricke auf Multiprozessoren bei der dot-net hat einen GC. Sie bleiben wollen Weg von der Itanium !
InformationsquelleAutor pngaz
SPARC (Solaris-Computern) ist eine andere Architektur (zumindest einige in der Vergangenheit), choke (geben Sie eine SIGBUS error), wenn Sie versuchen, verwenden Sie einen nichtlinearen Wert.
Nachtrag zu Martin York, malloc ist auch ausgerichtet, um die größte mögliche Typ, dh es ist sicher für alles, wie 'neu'. In der Tat, Häufig "neue" nur verwendet malloc.
InformationsquelleAutor JDonner
Ein Beispiel für die Ausrichtung in Ordnung Voraussetzung ist bei der Verwendung von Vektorisierung (SIMD -) Anweisungen. (Es kann verwendet werden, ohne die Ausrichtung in Ordnung, ist aber viel schneller, wenn Sie eine Art von Unterricht erfordert Ausrichtung).
InformationsquelleAutor Artur Soler
Durchgesetzt Speicher-alignment ist viel häufiger in RISC basierte Architekturen wie MIPS.
Die wichtigste denken, die für diese Arten von Prozessoren, AFAIK, ist wirklich ein speed-Problem.
RISC-Methodik wurde um eine einfache und schnelle Anleitung ( in der Regel eine Speicher-Zyklus pro Instruktion ). Dies bedeutet nicht unbedingt, dass es weniger Instruktionen als CISC-Prozessor mehr, dass es einfacher, schneller Anweisungen.
Viele MIPS-Prozessoren, obwohl die 8-byte-adressierbaren würde sein Wort ausgerichtet ( 32-bits in der Regel, aber nicht immer) dann die Maske aus den entsprechenden bits.
Die Idee ist, dass dies schneller zu tun, eine ausgerichtete Last, + bit-Maske als als zu versuchen zu tun, einen nichtlinearen Last.
In der Regel ( und natürlich dieses hängt wirklich davon ab, Chipsatz ), eine un-ausgerichtet-Last erzeugen würde, einen bus-Fehler, so dass RISC-Prozessoren anbieten würde, eine "unaligned load/store" der Unterricht aber das würde oft viel langsamer als die entsprechenden ausgerichtet, laden/speichern.
Natürlich noch nicht die Frage beantworten, warum Sie das mache.e welchen Vorteil hat mit Speicher von word-aligned geben Sie?
Ich bin kein hardware-Experte, und ich bin sicher, jemand hier geben können, eine bessere Antwort, aber meine zwei besten Vermutungen sind:
1. Es kann viel schneller zu Holen aus dem cache, wenn word ausgerichtet, weil viele caches organisiert sind, in den cache-Zeilen ( alles von 8 bis 512 bytes ) und als cache-Speicher ist in der Regel viel teurer als RAM, die Sie wollen, um das beste daraus zu machen.
2. Es kann viel schneller Zugriff auf die einzelnen Speicher-Adresse, da es Ihnen erlaubt zu Lesen, durch 'Burst-Modus' ( ich.e Holen Sie die nächste sequentielle Adresse, bevor es benötigt wird )
Hinweis: keines der oben genannten absolut unmöglich ist, mit nicht abgestimmten Geschäften, ich vermute ( obwohl ich nicht weiß ), dass eine Menge, es kommt auf die hardware-design-Entscheidungen und Kosten
InformationsquelleAutor zebrabox