Warum sind gepackte Strukturen nicht Teil der C-Sprache?

10

Jeder C-Compiler bietet die Möglichkeit, C-Strukturen (z . B. __attribute__ ((__packed__))oder #pragma pack()) zu "packen" . Jetzt wissen wir alle, dass Verpackung erforderlich ist, wenn wir Daten zuverlässig senden oder speichern möchten. Dies muss auch seit den ersten Tagen der C-Sprache erforderlich gewesen sein.

Ich frage mich also, warum gepackte Strukturen nicht Teil der C-Sprachspezifikation sind. Sie sind nicht einmal in C99 oder C11, obwohl die Notwendigkeit, sie zu haben, seit Jahrzehnten bekannt ist? Was fehlt mir? Warum ist es compilerspezifisch?

Grasbuschel
quelle
2
Sie sind nicht erforderlich, um reinen C-Code zu schreiben.
user253751

Antworten:

7

Ich denke, das liegt daran, dass es von der Kombination der verwendeten Ziel-CPU / des verwendeten Compilers abhängt. Dies bedeutet, dass es besser ist, eine Compiler-Direktive zu sein (da sie damit zusammenhängt) als ein Sprachaspekt, denn wie kann man das spezifizieren? Der einzige Weg, wie sie es schaffen könnten, ist die Vereinigung.

Der Artikel von Raymond gibt einen Einblick, warum dies so ist: http://www.catb.org/esr/structure-packing/

Frans Bouma
quelle
Sehr interessanter Artikel. (+1)
Giorgio
Welche Schwierigkeit würde es geben, Code sagen zu lassen: "Ich brauche eine Struktur mit 12 Bytes; Feld X muss sich als 32-Bit-Ganzzahl verhalten, die als Little-Endian mit vier Oktetten bei Offset 0 gespeichert ist. Feld Y muss sich als 64-Bit-Ganzzahl verhalten." als Oktettbytes Little-Endian bei Offset 4 "gespeichert? Code, der dies auf jeder Plattform handhabt, sollte nicht schlechter sein als das, was Compiler bereits für Bitfelder tun müssen, und in Fällen, in denen der Programmierer zufällig eine Ausrichtung angibt, die mit dem nativen Computer übereinstimmt, könnte dies viel effizienter sein. Auf anderen Maschinen wäre es weniger effizient, aber immer noch tragbar.
Superkatze
5

Es gibt drei Hauptfaktoren.

  1. Einige Prozessoren können nicht auf nicht ausgerichtete Daten zugreifen (z. B. eine Ganzzahl oder ein Float, die mit einer ungeraden Adresse beginnen). Der Versuch, dies zu tun, löst eine Ausnahme aus.
  2. Einige Prozessoren können auf nicht ausgerichtete Daten zugreifen, jedoch zu Leistungskosten.
  3. Auf die meisten Strukturen wird über einen einzigen Satz C / C ++ - Quellcode zugegriffen, und die Interoperabilität mit anderen Sprachen ist die Ausnahme und nicht die Regel.

Unter Berücksichtigung dieser Faktoren füllen sowohl der Standard- als auch alle C / C ++ - Compiler routinemäßig Strukturen auf, um eine optimale Ausrichtung für den Prozessor sicherzustellen, bieten jedoch auch Mechanismen, um diese bei Bedarf für Interop-Zwecke zu überschreiben.

Dies wurde keineswegs übersehen. Es ist sehr gut verstanden und die aktuelle Situation ist beabsichtigt. Die neuesten Versionen des C ++ - Standards bieten umfassende Unterstützung für die Behandlung von Ausrichtungsproblemen, mit denen Sie möglicherweise nicht vertraut sind.

david.pfx
quelle
Jedes Argument, das gegen gepackte Strukturen vorgebracht werden könnte, könnte auch verwendet werden, um zu rechtfertigen, dass Bitfelder zu einem optionalen Merkmal gemacht werden. Der Zugriff auf Mitglieder gepackter Strukturen wäre auf einigen Prozessoren langsam, auf anderen schnell, aber es ist weitaus komplizierter, wenn Compiler versuchen, Benutzercode-Problemumgehungen durch das Fehlen von Funktionen für nicht ausgerichteten Zugriff durch effizienteren Code zu ersetzen, als wenn Compiler Programmierern lediglich erlauben, anzugeben, was Sie brauchen.
Superkatze
@supercat: wofür argumentierst du (oder dagegen)? Ich verstehe es nicht
david.pfx
Ich bin der Meinung, dass Bitfelder optional sein sollten, aber wenn Bitfelder eine obligatorische Funktion sein sollen, wäre es sinnvoll, sie so zu erweitern, dass eine explizite Steuerung des Strukturlayouts möglich ist. Andernfalls besteht der Nettoeffekt darin, dass Compiler 90% der Arbeit erledigen müssen, die für die vollständige Kontrolle des Layouts erforderlich wäre, aber Programmierer nur 10% des Nutzens erhalten.
Superkatze
@supercat: Bitfelder sind Ganzzahlen und folgen denselben Regeln für die Reihenfolge des Bitlayouts wie Ganzzahlen: Implementierung definiert. Strukturelemente werden an deklarierten Zeichengrenzen angeordnet, möglicherweise mit eingefügter Packung. Sie sind konzeptionell ziemlich getrennt. [Sie müssen eine andere Frage stellen, wenn Sie Ihren Vorschlag erweitern möchten, aber ich glaube nicht, dass es überhaupt funktionieren würde.]
david.pfx
0

Es ist compilerspezifisch, da es nicht im Standard enthalten ist. Und es ist nicht im Standard enthalten, da es schwierig wäre, auf eine Weise zu spezifizieren, die für Compiler obskurer Plattformen mit erzwungenen Ausrichtungsbeschränkungen keinen großen Implementierungsaufwand erfordert.

Und keine dieser Bemühungen hat viel Rechtfertigung, da jeder Compiler / jede Plattform, um die sich jeder kümmert, der einen C89- oder späteren Compiler verwendet, bereits implementiert hat.

soru
quelle
2
??? Sie beantworteten die Frage "Warum nicht in der Standardsprache" mit "weil nicht in der Standardsprache" ...
Emilio Garavaglia
Das habe ich mir zuerst gedacht, aber andererseits könnte man das Feature wie "Wenn struct mit dem Schlüsselwort 'gepackt' definiert ist, ist seine Größe garantiert mit der hinzugefügten Größe jedes einzelnen Mitglieds identisch. Auf Plattformen, die dies nicht unterstützen unausgerichteter Speicherzugriff, Zugriff auf einen der Strukturelementwerte ist undefiniertes Verhalten. " Dies würde Entwicklern auf Plattformen ohne unausgerichteten Zugriff ermöglichen, zumindest die Strukturgröße und den Versatz jedes einzelnen Mitglieds zu kennen ...
grasbueschel
1
Es wäre möglich, einen nicht ausgerichteten Zugriff auf Systemen zu ermöglichen, die ihn in der Hardware nicht unterstützen, indem solche Strukturen als Array von Bytes implementiert und die erforderlichen Bitverschiebungen und &/ |Operationen ausgeführt werden, um die Werte jedes Felds zu lesen / schreiben.
Dan04
1
@ dan04: Auf vielen Prozessoren konnte ein Compiler Code für nicht ausgerichteten Zugriff generieren, der effizienter war als die Verwendung einer Folge von Byte-Lese- und Verschiebungen. Eine Syntax dafür würde es solchen Compilern erleichtern, effizienten Code zu generieren, als von ihnen zu verlangen, dass sie alle unterschiedlichen Methoden erkennen, mit denen Programmierer versuchen könnten, Code zu schreiben, um Bytes zu längeren Typen zusammenzusetzen.
Supercat