Padding Bytes in Byte struct
-
@Bushmaster sagte in Padding Bytes in Byte struct:
@DirkB sagte in Padding Bytes in Byte struct:
Z.B. kann nicht jeder Prozessor einfach auf jedes Byte eines Datenwortes zugreifen.
es soll prozessoren geben, die nur 16bit-speicherzugriffe können. zugriff auf eine ungerade adresse löst eine hardware exception aus.
Ist doch egal, denn das gilt dann ja auch für das Array.
-
Der Standard garantiert diesbezüglich nur (implizit), dass es nie führende Paddingbytes gibt.
-
Das ist mir alles klar. Allerdings, AFAIK:
- Padding ist nicht zwischen Array-Elementen erlaubt
uint8_t
muss, wenn es existiert, genau 8 bit gross sein, ebenfalls ohne Padding oder "unbenutzte" Bitschar
muss mindestens 8 Bit gross seinsizeof(char)
ist garantiert 1
Daraus folgt dann implizit z.B. dass
sizeof(uint8_t)
undalignof(uint8_t)
beide ebenfalls 1 sind.Wo ich mir nicht sicher bin ist ob der Compiler Padding "einfach so" einfügen darf, also auch wenn es nicht nötig wäre um das Alignment-Requirement zu erfüllen.
Wenn er das darf, dann ist es vom Standard aus nicht garantiert, ja.
Ist es in der Praxis relevant? Weiss ich nicht. Wenn man sich darauf verlässt sollte man vermutlich mindestens irgend einen Test haben der sicherstellt dass es auch funktioniert. Oder halt ein
uint8_t
Array verwenden wie ja schon vorgeschlagen wurde.
-
ich nehme an, wenn man eine struktur aus lauter chars hat, dann müsste sizeof die anzahl der elemente ergeben. kommt was größeres raus, hat der compiler was angehängt.
-
@hustbaer Die Anforderung no padding gilt für den Typ
uint8_t
an sich. Hat nichts damit zu tun was zwischen struct-members freigelassen werden darf.
-
@Swordfish sagte in Padding Bytes in Byte struct:
@hustbaer Die Anforderung no padding gilt für den Typ
uint8_t
an sich. Hat nichts damit zu tun was zwischen struct-members freigelassen werden darf.Ja, das verstehe ich schon.
Aber es gibt auch die Anforderung dass Arrays "dicht" sein müssen.
Und aus beiden Anforderungen zusammengenommen ergibt sich dann dassuint8_t
Arrays vollständig "dicht" sein müssen.Oder was meinst du? Ich verstehe nämlich gerade nicht ganz warum du mich darauf hinweist.
ps: Dass man die Garantie für Arrays nicht unbedingt auf structs ausweiten darf ist mir auch klar. Hatte ich denke ich auch schon vorhin geschrieben. Wo ich mir aber nicht sicher bin ist ob der Standard so formuliert ist dass der Compiler unnötiges Padding einfügen darf.
-
@hustbaer sagte in Padding Bytes in Byte struct:
dass der Compiler unnötiges Padding einfügen darf.
Wo?
-
@Bushmaster sagte in Padding Bytes in Byte struct:
es soll prozessoren geben, die nur 16bit-speicherzugriffe können. zugriff auf eine ungerade adresse löst eine hardware exception aus.
Aber auch da kommt man - mit etwas Aufwand - an die Daten.
Wird der Aufwand gescheut, gibt es Padding.
-
@DirkB sagte in Padding Bytes in Byte struct:
Aber auch da kommt man - mit etwas Aufwand - an die Daten.
ja, besonders schreibzugriffe auf uint8_t sind von übel, weil zuerst das 16bit-wort gelesen werden muss, weil man ja die eine hälfte nicht zerstören will.
-
@Swordfish sagte in Padding Bytes in Byte struct:
@hustbaer sagte in Padding Bytes in Byte struct:
dass der Compiler unnötiges Padding einfügen darf.
Wo?
Zwischen struct/class Membern.
Ich weiss nicht wie das im Standard genau formuliert ist, hab nicht nachgelesen. Eine "nicht-Standard" Quelle die ich auf die Schnelle gefunden habe hat es formuliert ala "may insert padding to meet the alignment requirements". Das wäre eine schwammige Formulierung die es weder explizit erlaubt noch explizit verbietet.
-
@Bushmaster sagte in Padding Bytes in Byte struct:
@DirkB sagte in Padding Bytes in Byte struct:
Aber auch da kommt man - mit etwas Aufwand - an die Daten.
ja, besonders schreibzugriffe auf uint8_t sind von übel, weil zuerst das 16bit-wort gelesen werden muss, weil man ja die eine hälfte nicht zerstören will.
Auf solchen Systemen darf es - wenn ich das alles richtig verstehe - sowieso kein
uint8_t
geben. Wegen memory model und so.
Denn Schreib- und Lesezugriffe aufmyUint8Array[0]
in einem Thread dürfen mit Schreib- und Lesezugriffen aufmyUint8Array[1]
in einem anderen Thread nicht kollidieren.
Zumindest ist das in C++ so, bitte korrigiert mich wenn das in C anders ist.Und das lässt sich einfach nur vernünftig machen wenn die CPU auch einzelne Bytes direkt schreiben kann. Wenn dazu mehrere Befehle nötig sind, kenne ich nur zwei Möglichkeiten das umzusetzen, und beide sind nicht "vernünftig":
- Atomics - viel zu teuer
- Hardware Transactional Memory - ebenfalls teuer und auf kaum einer CPU implementiert
Falls ich hier nen Denkfehler habe, bitte ich ebenfalls um Korrektur.
EDIT: OK, Annahme hier natürlich: das Ding unterstützt überhaupt echtes Multithreading. D.h. das Argument gilt natürlich nur für Systeme mit Multithreading. Hm. Schade
-
@hustbaer sagte in Padding Bytes in Byte struct:
Auf solchen Systemen darf es - wenn ich das alles richtig verstehe - sowieso kein uint8_t geben. Wegen memory model und so.
das könnte ja die cpu übernehmen.
angenommen byte-adresse 123 soll geschrieben werden. dann lädt die cpu das 16-bit-wort von word-adresse 61 ändert das low-byte und schreibt das wort wieder in den speicher. für den asm-programmierer ist das eine atomare operation, die bloß mehr taktzyklen braucht als ein 16-bit-schreibzugriff.
-
@Bushmaster sagte in Padding Bytes in Byte struct:
@hustbaer sagte in Padding Bytes in Byte struct:
Auf solchen Systemen darf es - wenn ich das alles richtig verstehe - sowieso kein uint8_t geben. Wegen memory model und so.
das könnte ja die cpu übernehmen.
angenommen byte-adresse 123 soll geschrieben werden. dann lädt die cpu das 16-bit-wort von word-adresse 61 ändert das low-byte und schreibt das wort wieder in den speicher. für den asm-programmierer ist das eine atomare operation, die bloß mehr taktzyklen braucht als ein 16-bit-schreibzugriff.Solche Systeme kenne ich nicht und AFAIK gibt es auch keine aktuellen solchen die irgendwie relevant wären. Alles was ich kenne was auf Assemblerebene direkt 8-Bit Bytes adressieren kann, kann entweder auch ohne "read-modify-write" direkt 8 Bit breit auf den Hauptspeicher zugreifen -- oder es hat einen Datencache dazwischen der sowieso immer ganze Cache-Lines aus dem Hauptspeicher liest und irgendwann wieder zurückschreibt.
Und bei den Systemen mit Datencache bleibt es dann auch egal ob du 8, 16 oder 32 Bit schreibst, weil die Cache-Lines nochmal deutlich breiter sind. Daher muss - wenn die Cache-Line nicht schon im Cache liegt - diese immer erst geladen werden bevor der geschriebene Wert hineingestanzt werden kann. Dazu haben solche CPUs dann üblicherweise sog. Store-Buffer, so dass sie mit der Bearbeitung des nächsten Befehls nicht warten müssen bis die Cache-Line geladen wurde und der Wert dort eingesetzt ist. Und auf das Zurückschreiben wird typischerweise sowieso nicht gewartet. Das passiert dann wenn es sein muss. z.B. wenn eine andere CPU/ein anderer Core die selbe Cache-Line haben möchte.
Daher bin ich einfach davon ausgegangen dass @DirkB Systeme meint wo man wirklich mehrere Assemblerbefehle dazu braucht und das ganze nicht mehr atomar ist.
Aber selbst wenn wir annehmen wir hätten so ein System. Dann wäre es IMO irgendwie komisch auf der einen Seite
uint8_t
anzubieten, was das arbeiten mituint8_t
Arrays recht langsam machen würde. Aber auf der anderen Seite dann Padding in Structs einzufügen, damit es in den Structs schneller geht.Padding zwischen mehreren direkt benachbarten
uint8_t
in einem Struct einzufügen ist für mich etwas was so grenzwertig beknackt ist, dass es vermutlich verschmerzbar ist wenn man es nicht berücksichtigt. Ich bin aber i.A. kein Fan von solchen Annahmen. Daher würde ich selbst bei dieser Annahme eine static Assertion oder notfalls einen Test schreiben so dass sichergestellt ist dass man mitbekommt wenn sie mal nicht mehr zutrifft. Aber ich würde niemand gröber beschimpfen nur weil er es nicht tut
-
@hustbaer sagte in Padding Bytes in Byte struct:
Solche Systeme kenne ich nicht und AFAIK gibt es auch keine aktuellen solchen die irgendwie relevant wären.
es geht noch schlimmer. bei einigen signalprozessoren ist jeder speicherzugriff immer 32bittig. erhöht man eine adresse um 1, ist man gleich 4 bytes weiter.
The C operation sizeof returns very different results on the C3x/C4x than on traditional RISC/CISC processors. The sizeof(char), sizeof(short), and sizeof(int) are all 1 since each occupies a single addressable unit that is thirty-two bits wide.
https://docs.rtems.org/releases/rtemsdocs-4.6.99.3/share/rtems/html/supplements/c4x/c4x00017.html
-
@Bushmaster sagte in Padding Bytes in Byte struct:
bei einigen signalprozessoren ist jeder speicherzugriff immer 32bittig.
Aber gerade die sind doch darauf spezialisiert Datenfolgen zu verarbeiten.
-
@Bushmaster sagte in Padding Bytes in Byte struct:
ist man gleich 4 bytes weiter.
Ne, Du bist 1 Byte weiter. </nitpickin>
-
@Swordfish sagte in Padding Bytes in Byte struct:
@Bushmaster sagte in Padding Bytes in Byte struct:
ist man gleich 4 bytes weiter.
Ne, Du bist 1 Byte weiter. </nitpickin>
ich hätte wohl octets schreiben sollen.
https://en.wikipedia.org/wiki/Octet_(computing)
-
@Bushmaster sagte in Padding Bytes in Byte struct:
@hustbaer sagte in Padding Bytes in Byte struct:
Solche Systeme kenne ich nicht und AFAIK gibt es auch keine aktuellen solchen die irgendwie relevant wären.
es geht noch schlimmer. bei einigen signalprozessoren ist jeder speicherzugriff immer 32bittig. erhöht man eine adresse um 1, ist man gleich 4 bytes weiter.
Ich weiss. Dann sind wir wieder bei meinem Beitrag von 18:52 und Systemen die vermutlich gar keinen
uint8_t
haben weil er nicht vernünftig umsetzbar ist.Auf den du "das könnte ja die cpu übernehmen" geantwortet hast. Dann hab ich dir erklärt dass Systeme wo die CPU das übernimmt kein Problem sind weil die Zugriffe dort typischerweise nicht langsam sind. Worauf du jetzt zu den Systemen zurückgehst die wir bereits abgehakt hatten (wo die CPU es eben nicht kann) und so tust als wäre das jetzt was neues was ich nicht bedacht hatte.
Mit dir zu diskutieren ist echt anstrengend und manchmal kommt es mir so vor als ob du absichtlich trollst. Dann wieder nicht. Und dann wieder schon. Soll sich mal einer auskennen.
-
@DirkB sagte in Padding Bytes in Byte struct:
@Bushmaster sagte in Padding Bytes in Byte struct:
bei einigen signalprozessoren ist jeder speicherzugriff immer 32bittig.
Aber gerade die sind doch darauf spezialisiert Datenfolgen zu verarbeiten.
DSPs können oft nur einen einzigen Datentyp laden/bearbeiten/speichern. Die sind dann aber auch selten das Ziel einer vollständigen und standardkonformen C11, C18 oder gar C++ Implementierung.
Und selbst bei DSPs die eher Features wie modernes SIMD Gedöns haben, mit unzähligen pack/unpack/shuffle Befehlen, wird man da kaum mit normalen
(u)intXX_t
Typen und Zeiger arbeiten. Sondern wie beim SIMD Gedöns spezielle Intrinsics für diese pack/unpack/shuffle Operationen verwenden. Wo dann wieder eigene Regeln gelten bezüglich Alignment, Atomizität etc.
-
@hustbaer sagte in Padding Bytes in Byte struct:
Mit dir zu diskutieren ist echt anstrengend und manchmal kommt es mir so vor als ob du absichtlich trollst. Dann wieder nicht. Und dann wieder schon. Soll sich mal einer auskennen.
vielleicht fühlst du dich angegriffen, weil du glaubst ich versuche dich zu widerlegen? ich sehe das aber nicht als streitgespräch. was ich schreibe ist als ergänzung gemeint. nichts für ungut.