Warum tut Polsterung haben, um eine Potenz von zwei ist?
Ich mache einige Beispiel-Programme zu erkunden, C und würde gerne wissen, warum die Struktur, die Polsterung kann getan werden, in der Kraft der zwei nur.
#include <stdio.h>
#pragma pack(push, 3)
union aaaa
{
struct bbb
{
int a;
double b;
char c;
}xx;
float f;
};
#pragma pack(pop)
int main()
{
printf("\n Size: %d", sizeof(union aaaa));
return 0;
}
Beim kompilieren
warning: alignment must be a small power of two, not 3 [-Wpragmas]
warning: #pragma pack (pop) encountered without matching #pragma pack (push) [-Wpragmas]
Scheint es, #pragma keine Auswirkungen. Die Ausgabe ist 24 nur. ich.e 4 byte ausgerichtet.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die kurze Antwort ist, dass die grundlegenden Objekte in den Prozessoren haben Größen, die klein sind Potenzen von zwei (z.B. 1, 2, 4, 8, und 16 Byte) und der Speicher ist organisiert in Gruppen, deren Größe ist eine kleine Potenz von zwei ist (z.B. 8 Byte), so müssen die Strukturen ausgerichtet werden, um gut zu funktionieren mit diesen Größen.
Die lange Antwort ist, dass die Gründe für diese geerdet sind) in Physik und Elementare Mathematik. Computer natürlich die Arbeit mit bits mit den Werten 0 und 1. Dies ist, weil es ist einfach zu design-physische Dinge, wechseln Sie zwischen zwei Werten: Hoch-und Niederspannung, der Anwesenheit von Ladung oder die Abwesenheit einer Ladung, et cetera. Die Unterscheidung zwischen den drei Werten ist schwieriger, weil Sie mehr sensible übergänge zwischen den Werten. So, wie die Computertechnik sich entwickelt hat im Laufe der Jahrzehnte, die wir verwendet haben, bits (binären Ziffern) statt alternativen wie trinary digits.
Kann, um größere zahlen, kombinieren wir mehrere bits. Also zwei bits können kombiniert werden, haben vier Werte. Drei bits haben acht Werte, und so weiter. Bei älteren Computern, manchmal bit Gruppe von sechs oder zehn auf einmal. Allerdings, acht gebräuchlich wurde, und ist im wesentlichen standard jetzt. Mit acht bit für ein byte nicht so starke körperlichen Grund, wie einige der anderen Gruppierungen, die ich beschreibe, aber es ist der Weg der Welt.
Weiteres Merkmal der Computer ist der Arbeitsspeicher. Sobald wir diese bytes wollen wir speichern eine Menge von Ihnen, in einem Gerät, das leicht zugänglich für den Prozessor, so können wir viele bytes in und aus dem Prozessor schnell. Wenn wir eine Menge von bytes, wir benötigen einen Weg, um den Prozessor zu sagen, Speicher die bytes, die der Prozessor Lesen oder schreiben möchte. Also der Prozessor braucht einen Weg, um die bytes.
Verwendet der Prozessor die bits für die Werte, daher wird es bits für Adresse Werte. Also die Speicher werden gebaut, um zu akzeptieren, bits, um anzugeben, welche bytes zur Versorgung des Prozessors, wenn der Prozessor liest oder welche bytes zu speichern, wenn der Prozessor schreibt. Was hat der Speicher mit diesen bits? Eine einfache Sache ist, um ein bit zur Steuerung einer Umschaltung der Signalwege zum Arbeitsspeicher. Der Speicher wird aus vielen kleinen teilen, das speichern von bytes.
Betrachten wir ein Ding, in das Speichergerät speichern können, ein byte, und betrachten zwei Dinge neben einander, sagen wir A und B. Wir können mit einem Schalter wählen Sie, ob wir wollen, dass das Ein byte-aktiv zu sein oder B byte aktiv zu sein. Betrachten wir nun vier dieser Dinge, die, sagen wir A, B, C und D. Wir können einen Schalter zu wählen, ob Sie den A-B-Gruppe oder die C-D-Fraktion. Dann einen anderen Schalter wählt A oder B (bei Verwendung der A-B-Gruppe) oder C oder D (wenn es mit der C-D) - Gruppe.
Dieser Prozess wird fortgesetzt: Jedes bit in einer Speicher-Adresse wählt eine Gruppe von storage-Einheiten zu verwenden. 1 bit wählt zwischen 2 store-Einheiten, 2 wählen Sie zwischen 4, 3 wählen Sie zwischen 8, 4 wählen Sie zwischen 16, und so weiter. 8 bit wählen Sie zwischen 256 storage-Einheiten, 24 bit wählen Sie zwischen 16,777,216 storage-Einheiten und 32-bit wählen Sie zwischen 4,294,967,296 storage-Einheiten.
Gibt es eine weitere Komplikation. Das verschieben der einzelnen bytes zwischen Prozessor und Speicher ist langsam. Stattdessen werden moderne Computer-organisieren-Speicher in größere Stücke, wie acht bytes. Sie können nur verschoben werden acht bytes gleichzeitig zwischen dem Speicher und dem Prozessor. Wenn der Prozessor anfordert, dass der Speicher liefern einige Daten, die der Prozessor sendet nur die hohen bits der Adresse—low drei bits wählen Sie einzelne bytes innerhalb von acht bytes, und Sie werden nicht an Speicher.
Dies ist schneller, da der Prozessor bekommt acht bytes in der Zeit würde es sonst nehmen, um die Speicher alle tun, die das einschalten der Versorgung ein byte, und es ist billiger, weil Sie nicht brauchen, die große Zahl von extra-Schalter, die es dauern würde, um unterscheiden der einzelnen bytes im Speicher.
Aber, jetzt heisst es der Prozessor hat keine Chance, eine einzelne byte aus dem Speicher. Wenn Sie eine Anweisung auszuführen, die auf einem einzelnen byte, die der Prozessor Lesen muss acht Byte aus dem Speicher und Verschiebe dann diese bytes, um in den Prozessor zu bekommen, der ein byte, die Sie wollen. Ebenso, um zwei oder vier bytes, die der Prozessor liest acht bytes und extrahiert nur die bytes, die Sie wollen.
Diesen Vorgang zu vereinfachen, Prozessor-Designer festlegen, dass Daten abgeglichen werden sollte, die in einer bestimmten Weise. In der Regel benötigen Sie zwei-byte-Daten (wie 16-bit-Ganzzahlen) ausgerichtet werden, um ein Vielfaches von zwei bytes, vier-byte-Daten (wie 32-bit Ganzzahlen und 32-bit-floating-point-Werten) zu sein, ausgerichtet auf ein Vielfaches von vier bytes und acht-byte-Daten ausgerichtet werden auf ein Vielfaches von acht bytes.
Dieser erforderlichen Ausrichtung hat zwei Effekte. Erstens, weil vier-byte-Daten kann nur gestartet werden, auf zwei Plätzen in einem acht-byte-chunk Lesen des Speichers (Anfang oder in der Mitte), der Prozessor-Designer müssen nur in Adern zu extrahieren Sie die vier bytes, die aus zwei Orten. Sie müssen nicht fügen Sie alle zusätzlichen Kabel zu extrahieren vier bytes von jedem der acht einzelnen bytes werden könnte Startplätze, wenn Sie die Ausrichtung durften. (Einige Prozessoren komplett verbieten laden nicht ausgerichtete Daten, und einige Prozessoren erlauben es aber langsam Methoden, um es zu entpacken, die mit weniger Leitungen, aber die Verwendung eines iterativen Algorithmus, der eine Verschiebung der Daten über mehrere Prozessor-Zyklen, also nichtlinearen Lasten sind langsam.)
Der zweite Effekt ist, dass, weil vier-byte-Daten kann nur gestartet werden, auf zwei Plätzen in einem acht-byte-chunk, es endet auch im inneren das Stück. Betrachten Sie, was passieren würde, wenn Sie versuchte zu laden vier bytes der Daten, begann im sechsten byte eines acht-byte-chunk. Die ersten zwei bytes werden in das Stück, aber die nächsten zwei bytes werden in den nächsten chunk im Speicher. Der Prozessor wäre zu Lesen, die zwei Stücke von Speicher, die unterschiedliche bytes, die von jedem von Ihnen und setzen diese bytes zusammen. Das ist viel langsamer als das Lesen nur ein chunk.
So, Speicher ist organisiert durch Potenzen von zwei, denn das ist die Natürliche Folge von bits und Prozessoren Ausrichtung erfordern, denn das macht memory access effizienter. Die Ausrichtung ist natürlich Potenzen von zwei, und das ist, warum Sie Ihre Struktur Größen besser arbeiten, wenn Sie sind Vielfache der Potenzen von zwei, die verwendet werden, für die Ausrichtung.
Weil sonst würde es keinen Sinn machen. Sie hinzufügen Polsterung an den Strukturen, weil die CPUs arbeiten schneller auf die Daten ausgerichtet (und auf einigen Architekturen, Sie arbeiten nicht bei allen auf nicht ausgerichtete Daten), und der Angleichung von Voraussetzungen für die verschiedenen Datentypen sind immer auf kleine Potenzen von zwei (zumindest auf jeder Architektur, die ich gehört habe).
Immer noch, wenn für einige seltsame Grund benötigen Sie beliebige Ausrichtung, nichts hindert Sie daran, das hinzufügen von dummy -
char
arrays in den richtigen stellen zur Durchsetzung Ihrer Ausrichtung (das ist mehr oder weniger das, was der compiler ist unter der Haube sowieso).Den Speicher-bus ist, nur so viele bytes breit, und es ist in der Regel eine Leistung von zwei bytes breit, denn das ist die maximale effektive Nutzung der bits in einem Feld
Einer drei-bit-Feld wie so
ist eine mögliche Darstellung von acht zahlen
Wenn Sie beschränkt sich auf die zahlen
Dann würden Sie verschwenden die höchsten um-bit, das wäre immer null. Hardware-und software-Designer in den Anfängen der Datenverarbeitung benötigt jedes bit, Sie greifen konnte, weil der Speicher war sehr teuer, so dass diese Art von Abfall entworfen wurde, aus dem system heraus.
Später, wenn der Speicher-Subsysteme wuchs, ausgerichtet Zugang billiger wurde, zu entwerfen. Ausgerichtet access erfordert, dass der start eines Daten-element auf bestimmte Grenzen zu reduzieren, die Anzahl der transfers zwischen den Speicher-bus und die Reduzierung der Anzahl von Berechnungen im bus-management.
"Die macht der zwei" Anforderung war eine Nebenwirkung der bus-Architektur, gepaart mit einer einfachen routine, versichert C-Daten-Strukturen, ausgerichtet ausgerichtet access-Grenzen.
Zwar gibt es physikalische Gründe, die computer-designs zugunsten memory-power-der-zwei-Speicher-Ausrichtungen, ist eine ebenso wichtige Voraussetzung ist, dass alle Speicher Ausrichtungen müssen gleichmäßig aufzuteilen in eine Zahl. Andernfalls, wenn z.B. ein struct benötigt werden, ausgerichtet auf ein Vielfaches von 7, die man brauchte, ausgerichtet auf ein Vielfaches von 8, und eine, die benötigt werden, ausgerichtet auf ein Vielfaches von 9, ein
union
mit allen drei Strukturen müssten angepasst werden, um ein Vielfaches von 504.Ist der normale Weg, dass die Teilbarkeit Anforderung gehandhabt wird, ist zu sagen, dass alle Ausrichtung Größen müssen zu unterteilen, einige große Potenz von zwei. Ein solcher Ansatz funktionieren würde, aber es wäre nicht die einzig mögliche Umsetzung. Man könnte, wenn man so geneigt, design-hardware, das funktioniert mit 120-byte-cache-Zeilen, und Sie ermöglichen die Objekte, die ausgerichtet werden, auf ein Vielfaches von 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60, oder 120 bytes. So ein design könnte tatsächlich sehr vernünftig von einem hardware-Standpunkt (jeder cache-Zeile gespeichert werden würde als 1024 bits, einschließlich 64-bit Fehler korrigieren, schreiben-tagging oder andere Informationen) und ermöglicht die effiziente Speicherung von 80-bit Real -, RGB-oder XYZ-triplets (von einem beliebigen numerischen Typ etwa 80-bit Real). Wenn man nicht verlangen, dass die physischen Adressen werden in der gleichen numerischen Reihenfolge als logische Adressen, die Schaltung, die erforderlich ist, um das map-120-byte-Bereiche an, die cache-Zeilen der wäre nicht allzu teuer. Auf der anderen Seite, außerhalb von spezialisierten Anwendungen, ist es unwahrscheinlich, dass die Vorteile der non-power-of-two-mappings würde ausreichen, um zu überwinden, Fragen der Kosten und der Markt-und Trägheit.
Laut GCC-Dokumentation (http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html) die pack-pragma verwendet wird, "Für die Kompatibilität mit Microsoft Windows-Compiler".
Wenn Sie suchen für die MS-Dokumentation über die Abstimmung (http://msdn.microsoft.com/en-us/library/ms253949(v=vs. 80).aspx), finden Sie, dass MSVC compiler stellt sicher, dass die Ausrichtung von Typen basierend auf der Größe der Daten; welche, wie erläutert, durch andere Beiträge, ist logisch immer eine Potenz von 2 ist.
Wenn Ihr problem ist, dass Sie müssen einige Phantasie Ausrichtung der Organisation der Daten (Zugriff auf einige schlecht konzeptioniert memory-mapped Peripherie), dann Ihr bestes, ist mit Handbuch Verpackung der Struktur durch hinzufügen von Feldern, hinzufügen der erforderlichen Polsterung.