Forum: Compiler & IDEs 32-Bit-µC: Möglichst viel uint8_t verwenden?


von Franz (Gast)


Lesenswert?

Mal ne Frage an euch. Bei einem 32-Bit-Mikrocontroller, wie z.B. dem 
ESP32, ist ja nach wie vor der RAM oft das Problem, wenn Projekte 
umfangreich werden. Wie handhabt ihr so "Wald-und-Wiesen-Variablen" wie 
z.B. Schleifenzähler? Man braucht ja ständig so eine Variable und weiß 
im Voraus, dass nur Werte von vielleicht 1 bis 10 vorkommen.
Meine erste Reaktion ist dann immer, uint8_t zu verwenden, damit RAM 
gespart wird. Aber eventuell ist das gar nicht der richtige Weg und man 
sollte uint32_t nehmen, weil der µC das nativ kann? Besser wäre sicher, 
der Compiler (gcc) würde selbst entscheiden, aber kann er das überhaupt?

von c-hater (Gast)


Lesenswert?

Franz schrieb:

> Mal ne Frage an euch. Bei einem 32-Bit-Mikrocontroller, wie z.B. dem
> ESP32, ist ja nach wie vor der RAM oft das Problem, wenn Projekte
> umfangreich werden. Wie handhabt ihr so "Wald-und-Wiesen-Variablen" wie
> z.B. Schleifenzähler? Man braucht ja ständig so eine Variable und weiß
> im Voraus, dass nur Werte von vielleicht 1 bis 10 vorkommen.
> Meine erste Reaktion ist dann immer, uint8_t zu verwenden, damit RAM
> gespart wird. Aber eventuell ist das gar nicht der richtige Weg und man
> sollte uint32_t nehmen, weil der µC das nativ kann? Besser wäre sicher,
> der Compiler (gcc) würde selbst entscheiden, aber kann er das überhaupt?

Das ist in den allermeisten Fällen scheißegal. Der Schleifenzähler wird 
mit einiger Wahrscheinlichkeit sowieso in einem MCU-Register landen und 
nicht im RAM. Da diese Register nunmal bei einer 32Bit-MCU eben 32Bit 
breit sind, spricht absolut nix dagegen, einfach das generische int oder 
unsigned int zu verwenden.

von Erwin (Gast)


Lesenswert?

Franz schrieb:
> Bei einem 32-Bit-Mikrocontroller, wie z.B. dem
> ESP32, ist ja nach wie vor der RAM oft das Problem, wenn Projekte
> umfangreich werden.

Programmieren lernen hilft wohl am besten ...

von PittyJ (Gast)


Lesenswert?

Versuche nicht, mit solchen 'Tricks' zu optimieren. Die Compiler können 
das alles besser. Schleifenzähler landen sowieso auf dem Stack, da spart 
man nichts.

Versuche lieber, die Algorithmen ordentlich zu machen. Das bringt mehr.

von c-hater (Gast)


Lesenswert?

PittyJ schrieb:

> Schleifenzähler landen sowieso auf dem Stack

Das wäre eher die Ausnahme als die Regel. Dazu muss innerhalb der 
Schleife schon ganz ordentlich was passieren...

Und wenn das passiert, spielt es wiederum kaum noch eine Rolle, wo genau 
der Schleifenzähler liegt oder wie groß er ist...

von Rolf M. (rmagnus)


Lesenswert?

Franz schrieb:
> Meine erste Reaktion ist dann immer, uint8_t zu verwenden, damit RAM
> gespart wird. Aber eventuell ist das gar nicht der richtige Weg und man
> sollte uint32_t nehmen, weil der µC das nativ kann?

Auf einem 32-Bitter lohnt sich das eher nicht. Erstens wird der 
Schleifenzähler sehr wahrscheinlich in einem Register gehalten, zweitens 
sind dort 8-Bit-Variablen ggf. sogar ineffizienter, da z.B. ein ARM gar 
nicht in 8 Bit rechnen kann. Er muss das im schlimmsten Fall durch 
Einfügen zusätzlicher Instruktionen nachbilden.

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

Schleifenzähler mit "int", Felder in Strukturen die später im RAM 
rumliegen mit (u)int_least(8|16|32|64)_t entsprechend des notwendigen 
Wertebereich und mit Rücksicht aufs Alignment in der Struktur 
angeordnet.

von MaWin (Gast)


Lesenswert?

Franz schrieb:
> ei einem 32-Bit-Mikrocontroller, wie z.B. dem
> ESP32, ist ja nach wie vor der RAM oft das Problem

Der ESP32 hat mindestens 320 kiB RAM.
Wenn dir das nicht reicht, dann machst du ziemlich sicher etwas extrem 
Spezielles, oder etwas extrem Falsches.

von (prx) A. K. (prx)


Lesenswert?

Andreas M. schrieb:
> Schleifenzähler mit "int", Felder in Strukturen die später im RAM
> rumliegen mit (u)int_least(8|16|32|64)_t entsprechend des notwendigen
> Wertebereich und mit Rücksicht aufs Alignment in der Struktur
> angeordnet.

Allgemeiner für Faule: Nicht nur Schleifenzähler in nativer Grösse, also 
"int" oder "unsigned", sondern generell alle lokalen skalaren Variablen.

Einzig auf 8-Bittern ist das ungünstig, da in diesem Fall der C Standard 
der nativen Grösse von Vars zuwider läuft. Will man das aufgrund 
Portabilität einrechnen, gibts die (u)int_fastN_t für lokale Vars.

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

(prx) A. K. schrieb:
> Einzig auf 8-Bittern ist das ungünstig, da in diesem Fall der C Standard
> der nativen Grösse von Vars zuwider läuft. Will man das aufgrund
> Portabilität einrechnen, gibts die (u)int_fastN_t für lokale Vars.

Ja das stimmt. Auf dem AVR kann man ne ganze Menge code sparen wenn in 
"if", "for" usw peinlich darauf achtet auf allen Seiten des 
Vergleichsoperators den für den Wertebereich passenden "..fast.." 
Datentyp verwendet.

von Oliver S. (oliverso)


Lesenswert?

Andreas M. schrieb:
> Auf dem AVR kann man ne ganze Menge code sparen wenn in
> "if", "for" usw peinlich darauf achtet auf allen Seiten des
> Vergleichsoperators den für den Wertebereich passenden "..fast.."
> Datentyp verwendet.

Das ist allerdings eine urban legend.

Die Typen der stdint.h sind ja nun nichts weiter als typedefs auf die 
C-Datentypen, und sind (nicht nur beim AVR) einfach nur typedefs auf die 
Typen ohne _fast. Das da ein Compiler in Schleifen sich einen 
"schnelleren" Typ aussuchen könnte, ist reines Wunschdenken.

Oliver

von Michael F. (Firma: IAR Systems) (michael_iar)


Lesenswert?

Oliver S. schrieb:
> Die Typen der stdint.h sind ja nun nichts weiter als typedefs auf die
> C-Datentypen, und sind (nicht nur beim AVR) einfach nur typedefs auf die
> Typen ohne _fast. Das da ein Compiler in Schleifen sich einen
> "schnelleren" Typ aussuchen könnte, ist reines Wunschdenken.

Moin,

der IAR Compiler für Arm (gerade mit v9.30.1 getestet) löst "_fast8" und 
"_fast16" unter der Haube anders auf, als die entsprechenden "normalen" 
Datentypen:

z.B.
1
...
2
#define __UINT8_T_TYPE__ unsigned char
3
...
4
#define __UINT16_T_TYPE__ unsigned short int
5
...
6
#define __UINT_FAST8_T_TYPE__ unsigned int
7
...
8
#define __UINT_FAST16_T_TYPE__ unsigned int
9
...

Gruß,
Michael

von Oliver S. (oliverso)


Lesenswert?

Michael F. schrieb:
> der IAR Compiler für Arm (gerade mit v9.30.1 getestet) löst "_fast8" und
> "_fast16" unter der Haube anders auf, als die entsprechenden "normalen"
> Datentypen:

Das mag schon sein. gcc macht das für x86 auf Linux auch, auf Windows 
aber nicht. YMMMV.

Andreas M. schrieb:
> AVR

Auf einem 8-bitter wie dem AVR kann das nichts bringen, denn da ist nun 
mal ein (u)int8_t der schnellste Datentyp, und für alle größeren gilt: 
je größer, desto langsamer.

Oliver

Beitrag #7118562 wurde von einem Moderator gelöscht.
von DerEgon (Gast)


Lesenswert?

blubblub schrieb im Beitrag #7118562:
> Seit ewigen Zeiten:
>
> typedef unsigned char uc;
> typedef unsigned int ui;
>
> Und aus die Maus.

Ist halt doof. Besonders, seitdem es die stdint.h gibt.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

blubblub schrieb im Beitrag #7118562:
> typedef unsigned char uc;
> typedef unsigned int ui;
>
> Und aus die Maus.

So ähnlich habe ich das auch lange gemacht (und teilweise noch heute).
Ich verwendete dann als short form u8, u16 ... als Type.

: Bearbeitet durch User
Beitrag #7118593 wurde von einem Moderator gelöscht.
von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Ganz dumme Idee(Hat sich aber Bewährt)

Temporäre Schleifenzähler(Wen der Speicher und die Register knapp 
werden), vor allem wenn sie gerade mal ein halbes Byte groß sind, 
verwende ich gerne Register von unbenutzten Pheripherien. etwa AD 
Zwischenregister, Port Interruptpolaritäts Register usw...
Ganz Favorisiert auch Timer CC oder Zählerregister die nicht gebraucht 
werden.. Davon liegen in den meisten Applikationen immer einige Brach, 
und sind auch noch nur 8 oder 16 Bit breit! (auch bei 32 Bit µC's)

Sind auch noch oft schneller als RAM-Zugriff, und wenn man mit DMA 
arbeitet, belegen sie kein DMA Kanal :-)
Also kann DMA auf Speicher zugreifen, während die CPU grad am 
Incrementieren ist usw...
Timer-Register mit Autoinkrement Funktion und Interrupt Auslösung bei 
"0" sind da ebenfalls sehr beliebt als Schlaufenzähler, da sie so 
Konfiguriert werden können das sie bei Abfrage grad direkt Inkrementiert 
werden, was dann ein Vergleichen und Inkrementieren erspart. Und der 
Interrupt wird auf Schleifenende-Handling gesetzt. Spart dann noch ein 
Sprungbefehl bei der Bedingung in der eine Schlaufe auch in der Schlaufe 
beendet werden soll.

73

von Oliver S. (oliverso)


Lesenswert?

blubblub schrieb im Beitrag #7118593:
> Einer meiner ersten benutzten Compiler konnte genau
> eine Variable in ein Register legen.
>
> register cx;

Jaja, die guten alten Zeiten. Das war bestimmt noch auf Lochkarten.
Ist zwar nett, aber heute doch völlig irrelevant.

Oliver

von DerEgon (Gast)


Lesenswert?

blubblub schrieb im Beitrag #7118593:
> Ne. Kein Compiler wird mit der stdint.h besser.

Der Compiler nicht, aber man muss nicht mehr so unwartbaren Rotz mit 
überflüssigen selbstdefinierten Typen schreiben, wie Du es tust.

Hast Du Dir für die anderen Datentypen, die C kennt, auch eigene Defines 
gefrickelt?

Wie wäre es mit "g" (Ganzzahl), "gg" (große Ganzzahl) anstelle von int 
und long?

"gp" (Ganzzahl positiv) statt unsigned int?

Oder mit "b" (Bruchzahl) und "gb" (große Bruchzahl) anstelle von float 
und double?

Oder mit "t" (Text) statt char?

"tz" statt char *, "gz" statt int *, "gpz" statt unsigned int * ...

Beitrag #7118673 wurde von einem Moderator gelöscht.
von (prx) A. K. (prx)


Lesenswert?

Oliver S. schrieb:
> Das da ein Compiler in Schleifen sich einen
> "schnelleren" Typ aussuchen könnte, ist reines Wunschdenken.

Kein Wunschdenken und genau das tut er. Genau genommen tut es allerdings 
derjenige, der das Include-Files dazu schreibt, und bei einer 32-Bit 
RISC für int_fast8_t einen 32-Bit Typ einsetzt, bei 8-Bit AVR aber einen 
8-bit Typ.

von Peter D. (peda)


Lesenswert?

MaWin schrieb:
> Der ESP32 hat mindestens 320 kiB RAM.

Dann lohnt sich natürlich keinerlei Mikro-Optimierung.

Franz schrieb:
> z.B. dem
> ESP32, ist ja nach wie vor der RAM oft das Problem, wenn Projekte
> umfangreich werden.

Wirklich?
Speicherst Du darin Telefonbücher ab?

von avr (Gast)


Lesenswert?

Es ist halt einfach Bad practise eigene Datentypen selbst zu definieren, 
die es in der stdint.h schon gibt. Steht in sämtlichen aktuellen Coding 
guide lines - da gibt's auch nichts zu diskutieren.

Kompatibilität wurde schon genannt. Fehlerrisiko bei Architekturwechsel 
ist ein anderer Punkt. "Not invented here" ist immer schlecht. Wer über 
seinen Tellerrand schauen kann, nimmt die weit verbreiteten, getesteten 
und erprobten Lösungen.

von (prx) A. K. (prx)


Lesenswert?

Oliver S. schrieb:
> gcc macht das für x86 auf Linux auch, auf Windows
> aber nicht. YMMMV.

x86 ist ein Grenzfall, weil diese Architektur auch in Registern mit 
8-Bit Datentypen zurecht kommt, besonders in der x86_64 Variante. 
Deshalb kann man bei int_fast8_t Gründe für beide Varianten finden - 8 
Bit weils in Register möglich ist, 32 Bit weil seit dem Pentium Pro 
bestimmte Ablauf-Abhängigkeiten der Mikroarchitekturen dafür sprechen.

: Bearbeitet durch User
von Ausrichter (Gast)


Lesenswert?

Franz schrieb:
> Meine erste Reaktion ist dann immer, uint8_t zu verwenden, damit RAM
> gespart wird.

uint8_t wird wahrscheinlich auf ARM im RAM auf 4 Byte aligned.
Schau dir einfach mal die Adressen von deinen Variablen an.

von Andreas M. (amesser)


Lesenswert?

Ausrichter schrieb:
> uint8_t wird wahrscheinlich auf ARM im RAM auf 4 Byte aligned.

Nein.

Oliver S. schrieb:
> Die Typen der stdint.h sind ja nun nichts weiter als typedefs auf die
> C-Datentypen, und sind (nicht nur beim AVR) einfach nur typedefs auf die
> Typen ohne _fast. Das da ein Compiler in Schleifen sich einen
> "schnelleren" Typ aussuchen könnte, ist reines Wunschdenken.

Nein.

Beim AVR ist uint_fast8_t "unsigned char", beim ARM und amd64 hingegen 
"unsigned int". Und genau so ist es auch definiert: der 
architekturspezifische Datentyp mit dem am schnellsten Operationen für 
einen Wertebereich von "0-255" durchgeführt werden können. Dem entgegen 
ist uint8_t auf allen Architekturen ein typedef auf "unsigned char". 
(Wenn unsigned char 8 bit hat, sonst existiert das typedef nicht) Ein 
uint_least8_t ist auf allen Architekturen, die 8-Bit Datenzugriffe 
unterstützen ebenfalls ein typedef auf "unsigned char". Es gibt aber 
z.B. DSP die können nicht weniger als 16 Bit. Da ist uint_least8_t ein 
typedef auf "int". (16 bit)

Wenn ich portablen Code schreiben möchte der eine Zahl zwischen 0 und 
255 und der sowohl auf AVR, ARM, x86, MSP430 oder sonstwas die 
bestmögliche Performance/Codegröße erreichen soll, dann nimmt man eben 
uint_fast8_t. Fertig. Und will man einen 8 bit Wert nicht nur temporär 
im Stack/Register verwenden, sondern irgendwo als Data/Bss/Heap 
speichern, dann nimmt man eben uint_least8_t für die Felddeklaration, 
dann läuft der Code auch auf den oben erwähnten DSP Architekturen ohne 
irgendwelche Klimpzüge.

Wenn man natürlich Projekte immer nur eng in einer Platform denkt und 
entwickelt, muss man darüber nicht nachdenken.

von Rolf M. (rmagnus)


Lesenswert?

Andreas M. schrieb:
> Ausrichter schrieb:
>> uint8_t wird wahrscheinlich auf ARM im RAM auf 4 Byte aligned.
>
> Nein.

Das würde der C-Standard auch verbieten. Das Alignment eines Datentyps 
kann nie größer sein als der Datentyp selbst, denn in einem Array müssen 
alle Elemente immer direkt aufeinander folgen, ohne Leerbytes 
dazwischen.

Andreas M. schrieb:
> Wenn ich portablen Code schreiben möchte der eine Zahl zwischen 0 und
> 255 und der sowohl auf AVR, ARM, x86, MSP430 oder sonstwas die
> bestmögliche Performance/Codegröße erreichen soll, dann nimmt man eben
> uint_fast8_t. Fertig. Und will man einen 8 bit Wert nicht nur temporär
> im Stack/Register verwenden, sondern irgendwo als Data/Bss/Heap
> speichern, dann nimmt man eben uint_least8_t für die Felddeklaration,
> dann läuft der Code auch auf den oben erwähnten DSP Architekturen ohne
> irgendwelche Klimpzüge.

Das ist eine sehr gute Beschreibung der Idee hinter diesen Datentypen. 
Es scheint erstaunlich wenige zu geben, die diesen eigentlich einfachen 
Sachverhalt erfassen.

Beitrag #7118954 wurde vom Autor gelöscht.
von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Das würde der C-Standard auch verbieten. Das Alignment eines Datentyps
> kann nie größer sein als der Datentyp selbst, denn in einem Array müssen
> alle Elemente immer direkt aufeinander folgen, ohne Leerbytes
> dazwischen.

Ob zwei getrennt definierte skalare chars 1 Byte auseinander liegen, 
oder 4, ist vom Standard m.E. nicht erfasst. Auch deshalb nicht, weil 
aufeinanderfolgend definierte Skalare nicht notwendigerweise in dieser 
Ordnung im Speicher liegen.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> denn in einem Array müssen
> alle Elemente immer direkt aufeinander folgen, ohne Leerbytes
> dazwischen.

Da wirds nun philosophisch, das Wesen der Leere betreffend. ;-)

Denn __float80 sind genau genommen nur 10 Bytes gross. Aber um nicht in 
die Bredouille zu kommen, tut der Compiler so, als wären sie 16 Bytes 
gross, und legt so effektiv Leerbytes dazwischen. Aber das ist halt eine 
andere Art von Leere, als jene, die du meinst.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

(prx) A. K. schrieb:
> Ob zwei getrennt definierte skalare chars 1 Byte auseinander liegen,
> oder 4, ist vom Standard m.E. nicht erfasst. Auch deshalb nicht, weil
> aufeinanderfolgend definierte Skalare nicht notwendigerweise in dieser
> Ordnung im Speicher liegen.

Das ist richtig, hat aber nichts mit Alignment zu tun. Aber wenn es 
einen Typ uint8_t gibt, muss man daraus auch Arrays bilden können, und 
da ist eben definiert, dass die Elemente direkt aufeinander folgen 
müssen. Das ist wiederum nur möglich, wenn das Alignment für uint8_t 1 
Byte ist, denn sonst wäre der Compiler ja gezwungen, zusätzliche Bytes 
zwischen den Elementen einzufügen. Ein uint8_t mit 4-Byte-Alignment 
lässt sich daher in C nicht standardkonform umsetzen.

(prx) A. K. schrieb:
> Rolf M. schrieb:
>> denn in einem Array müssen
>> alle Elemente immer direkt aufeinander folgen, ohne Leerbytes
>> dazwischen.
>
> Da wirds nun philosophisch, das Wesen der Leere betreffend. ;-)

Gemeint sind Bytes, die nicht zum Objekt selbst gehören, sondern nur 
Zwischenräume zwischen den Objekten auffüllen.

> Denn __float80 sind genau genommen nur 10 Bytes gross. Aber um nicht in
> die Bredouille zu kommen, tut der Compiler so, als wären sie 16 Bytes
> gross, und legt so effektiv Leerbytes dazwischen. Aber das ist halt eine
> andere Art von Leere, als jene, die du meinst.

Er legt genau genommen keine Leerbytes dazwischen, sondern macht sie zum 
Teil des Typs selbst. Das ist durchaus erlaubt, aber nicht für uint8_t, 
da der nicht größer sein kann als ein Byte - was wieder dazu führt, dass 
ein uint8_t mit einem Alignment von mehr als 1 Byte nicht 
standardkonform umsetzbar ist.

von Oliver S. (oliverso)


Lesenswert?

Andreas M. schrieb:
> Wenn ich portablen Code schreiben möchte der eine Zahl zwischen 0 und
> 255 und der sowohl auf AVR, ARM, x86, MSP430 oder sonstwas die
> bestmögliche Performance/Codegröße erreichen soll, dann nimmt man eben
> uint_fast8_t. Fertig.

Man muß halt im Hinterkopf haben, daß der tatsächliche Datentyp kein 
uint8_t sein muß, und alle möglichen daraus resultierende Unterschiede 
zum uint8_t beachten. So etwas wie
1
 if (i++ > 0 ) ...

funktioniert dann nicht mehr wie erwartet.

Oliver

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Das ist richtig, hat aber nichts mit Alignment zu tun.

Doch, aber an anderer Stelle. Bei der Speicherzuordnung im Linker können 
andere Alignment-Regeln gelten, als in der Sprache selbst.

von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Er legt genau genommen keine Leerbytes dazwischen, sondern macht sie zum
> Teil des Typs selbst.

Philosophische Betrachtungen sind nicht so dein Ding? ;-)

Meine Maschine fasst diese Bytes jedenfalls nicht an und schreibt brav 
ihre 10 Bytes und keines mehr. Also mögen sie zum Typ gehören, sind aber 
leer. Alignment-Bytes sind halt anders leer.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

(prx) A. K. schrieb:
> Philosophische Betrachtungen sind nicht so dein Ding? ;-)

Ich betrachte es halt "sprachphilosophisch".

> Also mögen sie zum Typ gehören, sind aber leer. Alignment-Bytes sind halt
> anders leer.

Sie sind genauso leer, nur sind sie eben nicht Teil des Typs. Das 
erkennt man z.B. auch per sizeof. So ist sizeof(__float80) nicht 10, 
sondern 16.

von mh (Gast)


Lesenswert?

Oliver S. schrieb:
> Andreas M. schrieb:
>> Wenn ich portablen Code schreiben möchte der eine Zahl zwischen 0 und
>> 255 und der sowohl auf AVR, ARM, x86, MSP430 oder sonstwas die
>> bestmögliche Performance/Codegröße erreichen soll, dann nimmt man eben
>> uint_fast8_t. Fertig.
>
> Man muß halt im Hinterkopf haben, daß der tatsächliche Datentyp kein
> uint8_t sein muß, und alle möglichen daraus resultierende Unterschiede
> zum uint8_t beachten. So etwas wie
>  if (i++ > 0 ) ...
>
> funktioniert dann nicht mehr wie erwartet.
>
> Oliver

Man muß auch im Hinterkopf behalten, dass der tatsächliche Datentyp ein 
uint32_t sein kann und damit mehr Speicherbandbreite braucht. Damit kann 
aus "fast" schnell "slow" werden, wenn die Bandbreite nicht mehr 
ausreicht.

von avr (Gast)


Lesenswert?

Das passiert aber nur auf einer 32-bit Architektur und dort sind 8-bit 
Zugriffe bei mir bekannten Architekturen niemals schneller als 32-bit.

In Strukturen kann es aus Speichergründen durchaus Sinn machen uint8_t 
statt der fast Variante zu verwenden, darum ging es hier aber nicht.

von mh (Gast)


Lesenswert?

avr schrieb:
> Das passiert aber nur auf einer 32-bit Architektur und dort sind 8-bit
> Zugriffe bei mir bekannten Architekturen niemals schneller als 32-bit.

Ja?! Deswegen hat der unit_fast8_t auch evtl. 32 Bit.
Und wenn es etwas wie SIMD gibt, wird es spannend was tatsächlich 
schneller ist.

von avr (Gast)


Lesenswert?

Ne, wird es nicht, außer du zeigst mir einen Compiler, der von sich auch 
aus SIMD Instruktionen verwendet.

Das schweift gerade vom Thema ab. Dieser Satz ist einfach Käse. Das 
passiert bei korrektem Einsatz von uint8_fast nicht.
mh schrieb:
> Damit kann aus "fast" schnell "slow" werden, wenn die Bandbreite nicht
> mehr ausreicht.

von mh (Gast)


Lesenswert?

avr schrieb:
> Ne, wird es nicht, außer du zeigst mir einen Compiler, der von sich auch
> aus SIMD Instruktionen verwendet.
gcc & clang

> Das schweift gerade vom Thema ab. Dieser Satz ist einfach Käse. Das
> passiert bei korrektem Einsatz von uint8_fast nicht.
Und warum nicht?

von Rolf M. (rmagnus)


Lesenswert?

avr schrieb:
> Ne, wird es nicht, außer du zeigst mir einen Compiler, der von sich auch
> aus SIMD Instruktionen verwendet.

Ich kann dir gleich drei nennen: GCC und die Compiler von Intel und 
Microsoft. Die Frage müsste ja schon fast eher lauten: Gibt's noch 
welche, die das nicht tun? Siehe 
https://www.google.com/search?q=automatic+vectorization

: Bearbeitet durch User
von avr (Gast)


Lesenswert?

Mag sein, hab ich aber im embedded Bereich noch nie beim GCC gesehen. 
Bisher habe ich in hot loops immer intrinsics nutzen müssen.

von int_ist_besser (Gast)


Lesenswert?

Auf keinen Fall uint8_t benutzen.
Hier mal ein Beispiel wo es langsamer ist als int:
https://godbolt.org/z/v8T96jz8d

von Andreas M. (amesser)


Lesenswert?

Das sind zwei vollkommen unterschiedliche Funktionen, die 
unterschiedliche Ergebnisse liefern. Warum sollten die die gleiche 
Laufzeit haben?

von MaWin (Gast)


Lesenswert?

int_ist_besser schrieb:
> Hier mal ein Beispiel wo es langsamer ist als int:

ziemlicher Käse ist es.

von W.S. (Gast)


Lesenswert?

Andreas M. schrieb:
> Wenn ich portablen Code schreiben möchte...

Wenn du so etwas schreibst, liegt die Vermutung nahe, daß du noch nie in 
dieser Verlegenheit warst. Also reine Theoretisiererei.

Wenn man wirklich portables Zeugs schreiben will, dann nimmt man das 
wenige, was die Sprachdefinition bietet und richtet sich danach. Immer 
in der Hoffnung, daß der zur jeweiligen Architektur gehörige Compiler 
das Richtige draus macht. Also keine programmiertechnischen 
"Husarenstücke" und z.B. int mit 16 Bit, auch wenn's vielleicht auf 
anderen Maschinen in 64 Bit gerechnet wird. Und wenn man Daten erzeugt 
oder bearbeitet, die auf Maschinen verschiedener Endianess richtig 
verstanden werden sollen, dann muß man sich überlegen, wie man das 
anstellt. Beispiel: eine .wav Datei auf verschiedenen Rechnern.

W.S.

von Lothar (Gast)


Lesenswert?

Franz schrieb:
> immer uint8_t verwenden

Bei einer struct aus gemischten uint8_t uint16_t uint32_t gibt es auf 
dem Cortex-M gute Chance auf Hardfault wegen Unaligned Access

von (prx) A. K. (prx)


Lesenswert?

Lothar schrieb:
> Bei einer struct aus gemischten uint8_t uint16_t uint32_t gibt es auf
> dem Cortex-M gute Chance auf Hardfault wegen Unaligned Access

Für das nötige Alignment sorgt der Compiler schon selbst.

: Bearbeitet durch User
von Lothar (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Für das nötige Alignment sorgt der Compiler schon selbst

Viele portierte Treiber z.B. Ethernet gehen aber über Pointer + Offset 
in eine Daten struct, da ist dann Auto Align nicht gut. Muss mal testen 
was gcc bei union macht ...

von (prx) A. K. (prx)


Lesenswert?

Lothar schrieb:
> Viele portierte Treiber z.B. Ethernet gehen aber über Pointer + Offset

Ja, aber derjenige weiss dann genau, was er tut. Oder sollte es.

Portablität von Daten über Architekturen hinweg ist eine vollkommen 
andere Baustelle, als alles, was hier bisher zur Sprache kam.

In Netzwerk-Code kann es vorkommen, dass ein Performance-Fan einen Frame 
auf eine MOD 4 == 2 Adresse legt, damit das Alignment vom IP-Header 
passt, weil der übliche Ethernet-Header 14 Bytes gross ist. Das ist dann 
aber schon Hardcore-Optimierung.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Lothar schrieb:
> Bei einer struct aus gemischten uint8_t uint16_t uint32_t gibt es auf
> dem Cortex-M gute Chance auf Hardfault wegen Unaligned Access

So ein Quatsch.

von Andreas M. (amesser)


Lesenswert?

W.S. schrieb:
> Immer in der Hoffnung, daß der zur jeweiligen Architektur gehörige
> Compiler das Richtige draus macht.

Wenn ich Software entwickle, dann hoffe ich nicht. Der Compiler macht 
das daraus, was ich will.

Den Rest von Deinem Anfeindungen lasse ich mal unkommentiert. Wenn Du 
Google bedienen könntest, dann würdest Du ziemlich schnell herausfinden 
was ich mache.

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Wenn man wirklich portables Zeugs schreiben will, dann nimmt man das
> wenige, was die Sprachdefinition bietet und richtet sich danach. Immer
> in der Hoffnung, daß der zur jeweiligen Architektur gehörige Compiler
> das Richtige draus macht.

Oder man lernt einfach die Sprache und weiß dann, was der Compiler 
draus macht. Das ist deutlich besser als hoffen.

> Also keine programmiertechnischen "Husarenstücke" und z.B. int mit 16 Bit,
> auch wenn's vielleicht auf anderen Maschinen in 64 Bit gerechnet wird. Und
> wenn man Daten erzeugt oder bearbeitet, die auf Maschinen verschiedener
> Endianess richtig verstanden werden sollen, dann muß man sich überlegen,
> wie man das anstellt. Beispiel: eine .wav Datei auf verschiedenen Rechnern.

Da vermischst du aber zwei Dinge, die man grundsätzlich sauber trennen 
sollte, nämlich programminterne Daten und solche, die zum Datenaustausch 
mit externen Systemen oder Peripherie da sind.
Für erstere ist der Datentyp zu bevorzugen, der eine für die gegebene 
Aufgabe ausreichende Größe hat und dabei am effizientesten umsetzbar 
ist, für letztere muss es natürlich die exakt richtige Größe sein. Da 
nimmt man, wenn es portabel sein soll, natürlich keinen int, sondern 
z.B. uint16_t. Um Endianness muss man sich dann eh gesondert kümmern. 
Aber auch das macht man natürlich nicht überall kreuz und quer im 
Programm, sondern nur an der Kommunikationsschnittstelle, die das 
erfordert.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Rolf M. schrieb:
> Da
> nimmt man, wenn es portabel sein soll, natürlich keinen int, sondern
> z.B. uint16_t. Um Endianness muss man sich dann eh gesondert kümmern.

Da hast du ungewollt mal wieder gezeigt, wie albern im Grunde solche 
Umbenennungen wie uint16_t sind. Solange man bloß rechnet, ist es egal, 
solange man sich auf das Zugesicherte veläßt (z.B. mindestens 16 bit) 
und wo es darum geht, Daten in vorgegebene Strukturen einzupassen, 
versagt sowas bereits beim int bzw. uint16_t, weil das eben die 
Endianness ignoriert. Und eine universelle Endianness hat bislang noch 
keiner erfunden.

W.S.

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> Und eine universelle Endianness hat bislang noch keiner erfunden.

Wie viele erfolgreiche Big Endian Implementierungen gibts denn noch? Da 
hilft auch der Umstand nicht weiter, dass man im Netzwerk mit Big Endian 
einfacher dran ist. ARM hält sich zwar aus dem Streit vornehm raus und 
lässt bei deren Cores beides zu, aber die realen Systeme sind m.W. heute 
alle Little Endian. Bleibt eigentlich nur POWER.

Die Apples sind allerdings nicht so meine Welt. Da wurde von Big Endian 
68K und PowerPC zwischendrin auf Little Endian x86 und dann ARM 
gewechselt. Das hätte man als Anwendungsentwickler eigentlich merken 
müssen.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Wie viele erfolgreiche Big Endian Implementierungen gibts denn noch?

Das gesamte Internet.

von c-hater (Gast)


Lesenswert?

MaWin schrieb:
> (prx) A. K. schrieb:
>> Wie viele erfolgreiche Big Endian Implementierungen gibts denn noch?
>
> Das gesamte Internet.

Das stimmt zwar, wirft aber die Frage auf: Wenn praktisch alle heute 
noch relevanten Systeme little endian benutzen, sollte man dann nicht 
mal endlich den Netzwerk-Scheiß den Realitäten anpassen und so enorme 
Mengen an Rechenzeit und damit direkt proportional Energie einsparen?

;o)

So viel zum Spaß, aber hier doch noch eine ernst gemeinte Frage: wer ist 
eigentlich ursprünglich auf die schwachsinnige Idee gekommen, hier big 
endian zu verwenden und warum? Little endian war eigentlich schon immer 
verbreiteter (weil's schlicht auf Hardware- und Software-Ebene letztlich 
deutlich praktischer ist, der einzige echte Nachteil ist und war ja 
immer nur die schlechtere Menschenlesbarkeit von Dumps).

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> Little endian war eigentlich schon immer
> verbreiteter

Viele in der Entstehungszeit des TCP/IP bestehenden Architekturen waren 
big endian.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> der einzige echte Nachteil ist und war ja
> immer nur die schlechtere Menschenlesbarkeit von Dumps

Was gerade bei Netzwerktechnik ein riesiger Nachteil wäre.

von (prx) A. K. (prx)


Angehängte Dateien:

Lesenswert?

MaWin schrieb:
> Was gerade bei Netzwerktechnik ein riesiger Nachteil wäre.

Reine Gewöhnung. Man muss nur von rechts nach links dumpen. Der VAX 
Assembler machte das in seinen Listings.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Reine Gewöhnung

Arabische Zahlen sind aber eben nun mal big-endian.

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> wer ist eigentlich ursprünglich auf die schwachsinnige Idee gekommen

Das ARPAnet entstand vermutlich auf einer big endian Maschine.

von (prx) A. K. (prx)


Lesenswert?

MaWin schrieb:
> Arabische Zahlen sind aber eben nun mal big-endian.

Mein Arabisch ist nicht so brilliant, aber soweit ich weiss, schreiben 
die von rechts nach links. Das wäre dann little endian. Also alles bloss 
ein grandioses Missverständnis, als unsere Vorfahren römische Schrift 
und arabische Zahlen kombinierten? ;-)

: Bearbeitet durch User
von Mombert H. (mh_mh)


Lesenswert?

MaWin schrieb:
> (prx) A. K. schrieb:
>> Reine Gewöhnung
> Arabische Zahlen sind aber eben nun mal big-endian.

Du meinst damit das in der westlichen Welt verwendete Dezimalsystem mit 
Arabischen Ziffern? Weil Zahlen in der deutschen Sprache sind weder Big 
noch Little-Endian oder dezimal ("dreizehntausendzweihundertelf").

@Autor von "Beitrag #7121643 wurde vom Autor gelöscht." (glaube A.K. 
(prx))
War der Inhalt falsch?

: Bearbeitet durch User
Beitrag #7121643 wurde vom Autor gelöscht.
von MaWin (Gast)


Lesenswert?

Mombert H. schrieb:
> Du meinst damit das in der westlichen Welt verwendete Dezimalsystem mit
> Arabischen Ziffern?

Ja?

> Weil Zahlen in der deutschen Sprache sind weder Big
> noch Little-Endian oder dezimal

Davon sprach ich nicht.

(prx) A. K. schrieb:
> Mein Arabisch ist nicht so brilliant

Darum ging es nicht.

von (prx) A. K. (prx)


Lesenswert?

Mombert H. schrieb:
> War der Inhalt falsch?

Ging zu weit vom Thema weg. Mir wärs ausserdem lieber, wenn ich nicht 
ahnungslos drüber spekulieren muss, sondern ein Kenner der Sprache sich 
äussert.

von MaWin (Gast)


Lesenswert?

(prx) A. K. schrieb:
> sondern ein Kenner der Sprache sich äussert.

Es geht nicht - und ging nie - um die arabische Sprache.

von (prx) A. K. (prx)


Lesenswert?

MaWin schrieb:
> Es geht nicht - und ging nie - um die arabische Sprache.

Mir aber schon. Ich nahm mir die Freiheit, neben den Zahlen auch deren 
Ursprung zu betrachten. ;-)

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Mir schon

Und warum machst du dafür nicht deinen eigenen Offtopic-Thread auf? Ich 
sehe jedenfalls keinen Zusammenhang zu diesem Thread.

von (prx) A. K. (prx)


Lesenswert?

Siehst du, genau deshalb hatte ich einen meiner Beträge gelöscht.

von ist doch logisch (Gast)


Lesenswert?

Weder noch.

Da wird man doch sowieso durch ein Array oder String iteririeren. Und 
sowohl strlen() als auch sizeof geben "size_t" zurück.

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Solange man bloß rechnet, ist es egal, solange man sich auf das
> Zugesicherte veläßt (z.B. mindestens 16 bit)
> und wo es darum geht, Daten in vorgegebene Strukturen einzupassen,
> versagt sowas bereits beim int bzw. uint16_t, weil das eben die
> Endianness ignoriert.

uint16_t ist halt nicht dafür gedacht, sämtliche Kommunikationsprobleme 
zu lösen. Mir wäre aber auch keine andere General-Purpose-Sprache 
bekannt, die solche Datentypen bietet.

c-hater schrieb:
> Little endian war eigentlich schon immer verbreiteter

Das Internet-Protokoll stammt von Anfang der 80er. Da sah die Welt in 
der Hinsicht etwas anders aus, gerade auch bei den Systemen, die mit dem 
Internet verbunden werden sollten. Die heute so verbreiteten 
Little-Endian-Architekturen spielten da allesamt keine Rolle oder 
existierten noch gar nicht.

von Mombert H. (mh_mh)


Lesenswert?

MaWin schrieb:
>> Weil Zahlen in der deutschen Sprache sind weder Big
>> noch Little-Endian oder dezimal
> Davon sprach ich nicht.

Ändert nichts daran, dass es relevant ist.

MaWin schrieb:
> (prx) A. K. schrieb:
>> Reine Gewöhnung
>
> Arabische Zahlen sind aber eben nun mal big-endian.
Wie A. K. gesagt hat: "Reine Gewöhnung". Wenn man von Kindern in der 
Schule erwarten kann, dass sie 13211 fließend in 
dreizehntausendzweihundertelf wandeln können. Dann kann man von Personen 
die sich mit Netzwerkdumps beschäftigen, ähnliche Gehirnleistung 
erwarten.

von MaWin (Gast)


Lesenswert?

Mombert H. schrieb:
> Wie A. K. gesagt hat: "Reine Gewöhnung". Wenn man von Kindern in der
> Schule erwarten kann, dass sie 13211 fließend in
> dreizehntausendzweihundertelf wandeln können. Dann kann man von Personen
> die sich mit Netzwerkdumps beschäftigen, ähnliche Gehirnleistung
> erwarten.

Bei Big-Endian brauche ich keine Gewöhnung, Wandlung oder ähnliche 
Gehirnleistung.
Niemand hat jemals gesagt, dass Little-Endian unlesbar wäre.
Aber Big-Endian ist unbestreitbar einfacher zu lesen.

von (prx) A. K. (prx)


Lesenswert?

MaWin schrieb:
> Aber Big-Endian ist unbestreitbar einfacher zu lesen.

Aber dann bitte auch mit passender Bitreihenfolge. Also Bit 0 oben und 
Bit 31 oder 63 unten. Sonst passt das nicht zusammen. Bytes von links 
nach rechts und Bits von rechts nach links zu nummerieren ist Unfug.

Motorola lernte das auf die harte Tour, weshalb die ab 68020 hinzu 
gekommenen Bitfelder von links nach rechts und die vorher schon 
bestehenden Einzelbits von rechts nach links nummeriert wurden.

IBM ist da konsequent und sowohl bei deren Mainframes als auch bei den 
POWER Prozessoren ist Bit 0 oben. TI ging noch einen Schritt weiter, 
indem bei den 16-Bit TI-990(0) die Bytes der 8-Bit Operationen nicht wie 
sonst üblich rechtsbündig in den Registern lagen, sondern linksbündig.

M.a.W: Die Dumps mögen big endian natürlicher wirken. Aber bei anderen 
Aspekten ist das genau umgekehrt.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Rolf M. schrieb:

> Das Internet-Protokoll stammt von Anfang der 80er. Da sah die Welt in
> der Hinsicht etwas anders aus, gerade auch bei den Systemen, die mit dem
> Internet verbunden werden sollten. Die heute so verbreiteten
> Little-Endian-Architekturen spielten da allesamt keine Rolle oder
> existierten noch gar nicht.

x86 existierte zu dieser Zeit bereits und war auch schon in in recht 
breitem Einsatz, jedenfalls dürfte die Zahl der existierenden 
x86-Systeme schon 1980 die Zahl aller anderen im praktischen Einsatz 
befindlichen Systeme mit mehr als 8 Bit deutlich überstiegen haben.

Aber OK, x86 gab's erst seit 1982 in einer notdürftigen 32Bit-Variante. 
Und mit dem Internet verbunden waren die Dinger tatsächlich eher selten, 
höchstens indirekt via "Terminal-DFÜ".

von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Das Internet-Protokoll stammt von Anfang der 80er.

Es entstand bereits in den 70ern.
https://en.wikipedia.org/wiki/Internet_Protocol#Version_history

c-hater schrieb:
> x86 existierte zu dieser Zeit bereits

In der Entstehungszeit noch nicht, da wurde ja nicht in 6 Tagen 
erfunden. Zudem waren x86er in diesem Zusammenhang vollkommen 
irrelevant. TCP/IP entstand auf Minicomputern. Auch die ersten Formen 
der Vernetzung von PCs hatten noch lange Zeit nichts mit TCP/IP zu tun, 
basierten auf NetBIOS und Novell.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

(prx) A. K. schrieb:
> Rolf M. schrieb:
>> Das Internet-Protokoll stammt von Anfang der 80er.
>
> Es entstand bereits in den 70ern.
> https://en.wikipedia.org/wiki/Internet_Protocol#Version_history

Ich hatte mich jetzt auf den ersten RFC für IPv4 von 1980 bezogen. Das 
hat's für mich offiziell gemacht. Aber stimmt natürlich, Entwicklung und 
damit wohl auch die Entscheidung für big endian gab es schon deutlich 
früher.

Beitrag #7122442 wurde vom Autor gelöscht.
von W.S. (Gast)


Lesenswert?

c-hater schrieb:
> So viel zum Spaß, aber hier doch noch eine ernst gemeinte Frage: wer ist
> eigentlich ursprünglich auf die schwachsinnige Idee gekommen, hier big
> endian zu verwenden und warum?

Was ist "hier"? Meinst du in diesem Forum? Und "verwenden"?

Ich selber habe lange Zeit die Fujitsu FR benutzt und die waren damals 
schneller und auch billiger als die damaligen ARM's oder die kleineren 
und inzwischen ausgestorbenen NEC 78K3 und K4. Eben deshalb habe ich 
immer mit Systemen verschiedener Endianness zu tun gehabt einschließlich 
solcher Dinge, die auf beiden Seiten funktionieren mußten - und jetzt 
kommen mir hier einige Jungspunde vor die Nase, die meinen, daß man mit 
uint16_t die ultimative Portabilität gefunden hätte, obwohl sie kaum 
etwas anderes als Atmel AVR und STM32 und den GCC gesehen haben und 
Assembler für einen neuen Blumendünger halten oder sich gar zu der 
Aussage hinreißen lassen "ich programmiere nicht auf Registerebene".

Ganz generell kann man sagen, daß es auch in der Prozessorgestaltung 
historisch gewachsene Dinge gibt, wie z.B. die Endianness, die zwei 
getrennte Welten (Motorola versus Intel) bewirkt hatten. Da hast du 
zumindest die historischen Wurzeln zu deiner Frage. Ich bin auch nicht 
recht froh über darüber, daß gar viele Architekturen inzwischen 
ausgestorben sind. Anstelle von Synergie-Effekten sieht man inzwischen, 
daß der geistige Horizont der Leute kleiner geworden ist. Setze mal 
einen der Programmierer, die sich hier großartig vorkommen, an ein 
Projekt mit einem µC von Freescale. Huch, das ist ja kein STM32!

W.S.

von Andreas M. (amesser)


Lesenswert?

W.S. schrieb:
> Eben deshalb habe ich
> immer mit Systemen verschiedener Endianness zu tun gehabt einschließlich
> solcher Dinge, die auf beiden Seiten funktionieren mußten - und jetzt
> kommen mir hier einige Jungspunde vor die Nase, die meinen, daß man mit
> uint16_t die ultimative Portabilität gefunden hätte

Kodierung von Daten auf Netzwerken, Bussen etc hat nur am Rande was mit 
Portabilität ein Applikation zu tun. Das Ausgangsthema dieses Threads 
sind innerhalb des selben Systems verwendete Variablen und Felder. Und 
da ist die Byte-Order vollkommen irrelevant. Wenn es um Datenaustausch 
mit anderen Systemen geht, dann muss man sich natürlich Gedanken um die 
Kodierung der Daten machen. Wenn man dann die entsprechenden uint<n>_t 
Typen zusammen mit gepackten Strukturen verwendet dann funktioniert das 
ganz gut und bleibt lesbar. Manche finden es besser wenn man die Bytes 
händisch wieder zusammensetzt. Wenn man dafür die uint<n>_t typen in 
gepackten aber ausgerichten Strukturen benutzt tut sich der Compiler 
einfacher beim optimieren.

W.S. schrieb:
> etwas anderes als Atmel AVR und STM32 und den GCC gesehen haben und
> Assembler für einen neuen Blumendünger halten oder sich gar zu der
> Aussage hinreißen lassen "ich programmiere nicht auf Registerebene".

Wo steht das hier im Thread? Btw. Kannst Du denn AVR, 8051, ARM, LX6 und 
Risc-V Assembler nicht nur lesen sondern auch schreiben? Wenn nicht dann 
würde ich mal ganz still mit solcher Selbstbeweihräucherung sein.

von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> und jetzt
> kommen mir hier einige Jungspunde vor die Nase, die meinen, daß man mit
> uint16_t die ultimative Portabilität gefunden hätte,

Abgesehen davon, daß du das Thema "endianess" hier in dem Thread 
aufgebracht hast, hat das eigentlich nie jemand gemeint oder behauptet.

Das die stdint.h-Datentypen keine systemübergreifende Kompatibilität 
beim Datenaustausch bieten, und auch nie dafür gedacht waren, dürfte so 
ziemlich jedem klar sein. Nur dir nicht.

Die bieten einfach nur Datentypen für das jeweilige System in einer 
definierten Bitbreite. Klingt einfach, ist auch so.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Andreas M. schrieb:
> Wenn man dann die entsprechenden uint<n>_t Typen zusammen mit gepackten
> Strukturen verwendet dann funktioniert das ganz gut und bleibt lesbar.

Allerdings kann nicht jede CPU problemlos auf Datentypen mit falschem 
Alignment zugreifen.

von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Allerdings kann nicht jede CPU problemlos auf Datentypen mit falschem
> Alignment zugreifen.

Bei gepackten Strukturen schon.

von (prx) A. K. (prx)


Lesenswert?

MaWin schrieb:
> Bei gepackten Strukturen schon.

Die CPU selbst nicht unbedingt und einen Sprachstandard für gepackte 
Strukturen gibt es m.W nicht. Wenn der Compiler es unterstützt, die CPU 
aber nicht, baut er sich die Zugriffe eben umständlich zurecht.

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

(prx) A. K. schrieb:
> und einen Sprachstandard für gepackte Strukturen gibt es m.W nicht. Wenn
> der Compiler es unterstützt, die CPU aber nicht, baut er sich die
> Zugriffe eben umständlich zurecht.

Ja eben dass ist ja die Aufgabe des Compilers. GCC und clang setzen 
beide das Alignment von Felder in gepackten Strukturen erst mal auf 1. 
Damit machen die erstmal nur noch Bytezugriffe, muss man dann nicht 
händisch machen. Kann man trotzdem drüber diskutieren. Manche bevorzugen 
Bytegymnastik. Hat auch seine Vorteile, steht dann explizit da. Ob ein 
ARM unaligned Speicherzugriff kann oder nicht hängt auch von den 
Einstellungen der MPU oder MMU ab. In Strongly Ordered oder Device 
Memory getaggten Bereichen ist das grundsätzlich nicht zulässig.

von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Rolf M. schrieb:
>> Allerdings kann nicht jede CPU problemlos auf Datentypen mit falschem
>> Alignment zugreifen.
>
> Bei gepackten Strukturen schon.

Der CPU ist egal, ob ein float in einer gepackten Struktur steht oder 
nicht. Von Strukturen weiß die nix.

Andreas M. schrieb:
> Ja eben dass ist ja die Aufgabe des Compilers. GCC und clang setzen
> beide das Alignment von Felder in gepackten Strukturen erst mal auf 1.

Was passiert denn, wenn ich über einen Zeiger auf das Element zugreife?
Generell bin ich bei gepackten Strukturen vorsichtig. Die haben bei mir 
in der Vergangenheit schon zu sehr merkwürdigen Verhaltensweisen 
geführt.

von (prx) A. K. (prx)


Lesenswert?

Wer möchte, der kann es auf dem PC ausprobieren. Steht Bit 18 von CR0 
auf 1, kann man mit Bit 18 von EFLAGS den Alignment Check in Ring 3 aus 
und einschalten.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

ARM Cores vor ARMv5, also auch die früher beliebten Mikrocontroller mit 
ARMv4 ARM7TDMI Cores, hatten eine sehr kreative Art, mit Alignment 
umzugehen. Damals waren die ARM Cores sehr einfach aufgebaut und alle 
Load-Daten liefen unweigerlich durch den Barrel Shifter, gesteuert über 
die Bits 0..1 der Adresse. Der rotierte das adressierte Byte passend ins 
unterste Byte des Registers. Der einzige Unterschied zwischen Byte- und 
Word-Load bestand in der Maskierung der Bits 8..31.

Das ist allerdings nicht immer das, was man von einem misaligned Load 
erwartet, d.h. die Daten, die man auf diese Art erhält, sind Schrott, 
wenn sie eine Wortgrenze überschreiten.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Von Strukturen weiß die nix.

Aber der Compiler, ihr Superspezialisten.

Gepackte Strukturen sind ein Compiler-/Sprachkonstrukt. Das hat mit der 
CPU überhaupt nichts zu tun.
Und der Compiler stellt sicher, dass es zu keinen Traps kommt.

Mann mann mann...

von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Gepackte Strukturen sind ein Compiler-/Sprachkonstrukt. Das hat mit der
> CPU überhaupt nichts zu tun.

Eben, genau das schrieb ich ja. Du hattest das Gegenteil behauptet.

> Mann mann mann...

Dito.

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

Rolf M. schrieb:
> Was passiert denn, wenn ich über einen Zeiger auf das Element zugreife?
> Generell bin ich bei gepackten Strukturen vorsichtig. Die haben bei mir
> in der Vergangenheit schon zu sehr merkwürdigen Verhaltensweisen
> geführt.

Das kommt auf den Zeiger an. Um genau zu sein, darfst du keinen 
"normalen" Zeiger auf ein Feld in einer gepackten Struktur setzen. 
Nehmen wir mal folgendes an:
1
struct  __attribute__((packed)) P {
2
uint8_t  a;
3
uint16_t b;
4
uint32_t c;
5
};

Dann wäre die folgende Definition falsch
1
struct P my_p;
2
uint32_t * my_ptr = &(my_p.c)

my_p.c ist als 32-Bit Integer ohne Alignment definiert während my_ptr 
als Zeiger auf ein 32 Bit Integer mit Standardalignment deklariert ist. 
D.h. wenn man (*my_ptr) schreiben würde, dann geht der Compiler davon 
aus, das die Adresse in my_ptr auf 4-Byte Grenzen ausgerichtet ist. Das 
geht dann krachen, weil wir ja die Adresse von my_p.c reingeschrieben 
haben, welche hier nicht auf eine 4-Byte Grenze liegt. Man kann sich 
aber Zeiger auf solche Integer definieren:
1
typedef uint32_t uint32_unaligned_t __attribute__((aligned(1)));
2
3
struct P my_p;
4
uint32_unaligned_t *proper_ptr = &(my_p.c);

Ich habe gerade mal ein bischen mit den Compilern herumgespielt. 
Aktuelle GCC Versionen geben jetzt sogar eine Warning aus. War früher 
nicht so. Allerdings scheint der Compiler in manchen Fällen trotzdem 
lauffähigen Code zu produzieren. Für mein Beispiel von oben in "-O2" 
gibt er das korrekte aus, bei -O0 jedoch nicht.

https://godbolt.org/z/4x4KfYvz1

von Rolf M. (rmagnus)


Lesenswert?

Das klingt alles recht murksig. Gerade deshalb meide ich gepackte 
Strukturen doch lieber. Ich gehöre da eher zu dieser Kategorie:

Andreas M. schrieb:
> Manche bevorzugen Bytegymnastik.

Das bekommt man dann deutlich weniger abhängig vom Compiler und der CPU 
hin.

von Michael F. (Firma: IAR Systems) (michael_iar)


Lesenswert?

(prx) A. K. schrieb:
> Wenn der Compiler es unterstützt, die CPU
> aber nicht, baut er sich die Zugriffe eben umständlich zurecht.

Moin,

korrekt und der erzeugte Code kann da teilweise recht ineffizient 
werden.

Hier mal ein Beispiel für eine "normale" und gepackte Struktur für den 
MSP430 & GCC:
https://godbolt.org/z/TKvr5MTEK

Gruß,
Michael

von Andreas M. (amesser)


Lesenswert?

Rolf M. schrieb:
> Das bekommt man dann deutlich weniger abhängig vom Compiler und der CPU
> hin.

Ja, die "__attribute__" Syntax ist eben GCC specifisch. Wenn die 
Strukturen gepackt, aber z.b. immer auf einer z.B. 4-Byte grenze im RAM 
liegen (habe ich hier ganz oft) dann kann man das ebenfalls per 
attribute syntax definieren. Das bietet Optimierungspotential, weil der 
GCC dann selbsttändig entscheidet, ob er ein Feld Byte-Weise lesen muss, 
oder ob er einen normalen Zugriff verwenden kann. Das kann sehr viel 
Code sparen. Ein byteweises zusammensetzen von 32-Bit sind immerhin 7 
Instruktionen, bei einem normalen Zugriff ist das 1 Instruktion + evtl. 
1 Instruktion (Byte-Order Anpassung). Das konsequent umgesetzt hat in 
unseren Firmwaren zwei bis dreistellig kByte Code reduziert.

Mit C++ lässt ein Bytegymnastik Parser ja auch schön kapseln. Aber eine 
wirklich eleganten Weg solche Datenstrukturen für den Transport zu 
definieren/dekodieren/kodieren hab ich noch nicht gefunden. Alle Ansätze 
die ich bisher gesehen habe, haben immer irgendwelche "Kanten".

von Nils (Gast)


Lesenswert?

Andreas M. schrieb:
> Ich habe gerade mal ein bischen mit den Compilern herumgespielt.
> Aktuelle GCC Versionen geben jetzt sogar eine Warning aus. War früher
> nicht so. Allerdings scheint der Compiler in manchen Fällen trotzdem
> lauffähigen Code zu produzieren.

Das ist ein sehr wichtiger Hinweis, Andreas.

Ich möchte noch hinzufügen: Man sollte sich nicht darauf ausruhen, das 
die CPU, die man einsetzt, mit unaligned Zugriffen klar kommt.

Gerade beim Cortex-M kann man sich böse Hardfaults eintreten.

Ja, die CPU kann unaligned Zugriffe, aber nicht beim LDRD Befehl. Wenn 
der Compiler meint zwei Speicherzugriffe auf ein Befehl zu optimieren, 
dann knallt es trotzdem.

von Rolf M. (rmagnus)


Lesenswert?

Michael F. schrieb:
> Hier mal ein Beispiel für eine "normale" und gepackte Struktur für den
> MSP430 & GCC:

Da hast du allerdings auch vergessen, Optimierungen einzuschalten. Mit 
-O1 sieht der Code schon erheblich kürzer aus.

: Bearbeitet durch User
von Michael F. (Firma: IAR Systems) (michael_iar)


Lesenswert?

Rolf M. schrieb:
> Da hast du allerdings auch vergessen, Optimierungen einzuschalten.

Jein... ;-)

Mit abgeschalteter Optimierung bekommt man zugegebenermaßen den 
worst-case, aber das Beispiel zeigt (meiner Meinung nach) ganz gut, dass 
man sich nicht immer blind darauf verlassen sollte, dass der Compiler 
den geschriebenen C/C++ Code schon irgendwie sinnvoll implementiert. Ein 
paar gesparte Bytes im RAM durch eine gepackte Struktur können je nach 
MCU Architektur zu langsameren & größeren Code führen und man sollte 
sich dieser möglichen Auswirkungen bewusst sein, bzw. im Zweifelsfall 
den generierten Code anschauen :-)

Gruß,
Michael

von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Eben, genau das schrieb ich ja. Du hattest das Gegenteil behauptet.

Nein, das habe ich nicht. Lies bitte meine Texte und versuche sie auch 
zu verstehen.

von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Rolf M. schrieb:
>> Eben, genau das schrieb ich ja. Du hattest das Gegenteil behauptet.
>
> Nein, das habe ich nicht. Lies bitte meine Texte und versuche sie auch
> zu verstehen.

Vielleicht solltest du dann schreiben, was du meinst und nicht was 
anderes. Zur Kommunikation gehören immer zwei Seiten. Hier steht es 
schwarz auf weiß:

MaWin schrieb:
> Rolf M. schrieb:
>> Allerdings kann nicht jede CPU problemlos auf Datentypen mit falschem
>> Alignment zugreifen.
>
> Bei gepackten Strukturen schon.

Wenn eine CPU nicht mit falschem Alignment zugreifen kann, dann kann sie 
das eben nicht, auch in gepackten Strukturen nicht. Der Compiler kann 
den Code ggf. so umbauen, dass eben keine falsch alignten Zugriffe auf 
den Speicher passieren, aber das ist eine andere Geschichte.
… wie du dann im Anschluss ja auch ganz richtig schreibst:

MaWin schrieb:
> Gepackte Strukturen sind ein Compiler-/Sprachkonstrukt. Das hat mit der
> CPU überhaupt nichts zu tun.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

MaWin schrieb:
> Rolf M. schrieb:
>> Eben, genau das schrieb ich ja. Du hattest das Gegenteil behauptet.
>
> Nein, das habe ich nicht. Lies bitte meine Texte und versuche sie auch
> zu verstehen.
Ich habe deine Texte nochmal gelesen und verstehe sie wohl genauso wie 
Rolf. Wenn das nicht das ist, was du sagen wolltest musst du vielleicht 
ein paar mehr Worte schreiben.

MaWin schrieb:
> Rolf M. schrieb:
>> Allerdings kann nicht jede CPU problemlos auf Datentypen mit falschem
>> Alignment zugreifen.
>
> Bei gepackten Strukturen schon.
Wie soll man das anders interpretieren als "Bei gepackten Strukturen 
kann die CPU problemlos auf Datentypen mit falschem Alignment 
zugreifen." Wenn du sagen wolltest "Der Compiler regelt das für gepackte 
Strukturen", dann solltest du das auch sagen ...

von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Hier steht es schwarz auf weiß:

Ja. Dann zitiere es bitte auch vollständig.


Rolf M. schrieb:
> Andreas M. schrieb:
>> Wenn man dann die entsprechenden uint<n>_t Typen zusammen mit gepackten
>> Strukturen verwendet dann funktioniert das ganz gut und bleibt lesbar.
>
> Allerdings kann nicht jede CPU problemlos auf Datentypen mit falschem
> Alignment zugreifen.


Darauf antwortete ich:

MaWin schrieb:
> Bei gepackten Strukturen schon.


DU bist derjenige, der fälschlicherweise die CPU ins Spiel brachte.
Die CPU hat überhaupt nichts mit gepackten Strukturen zu tun und es 
kommt auch nicht zu Traps, wie von DIR behauptet.

von MaWin (Gast)


Lesenswert?

mh schrieb:
> Wie soll man das anders interpretieren

Indem man das gesamte Gespräch liest, und nicht nur den Teil, der extra 
so herausgepickt wurde, um mich dumm dastehen zu lassen.

Antworten bedingen immer, dass man die beantworteten Texte auch liest. 
Und zwar alle relevanten, rekursiv.

von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> DU bist derjenige, der fälschlicherweise die CPU ins Spiel brachte.

Mit anderen Worten: Du hast mein Posting nicht richtig gelesen, 
beschwerst dich aber, dass ich deins angeblich nicht richtig gelesen 
hätte. Und was sollte daran falsch sein? Stimmt es etwa nicht, dass 
nicht jede CPU problemlos auf Datentypen mit falschem Alignment 
zugreifen kann?
Klar mögen Compiler das vielleicht geradeziehen, aber das hättest du ja 
schreiben können. Und wie auch schon erwähnt wurde, ist das nichts 
standardisiertes, sondern vollständig compilerspezifisch. Also ist die 
pauschale Aussage, dass "der Compiler" das macht, auch so nicht richtig.

> Die CPU hat überhaupt nichts mit gepackten Strukturen zu tun und es
> kommt auch nicht zu Traps, wie von DIR behauptet.

Zunächst einmal habe ich Traps überhaupt nicht erwähnt, also erzähl 
nicht, ich hätte da irgendwas behauptet. Und zweitens habe ich 
tatsächlich schon das Problem gehabt, dass die CPU in eine Exception 
gelaufen ist wegen der Nutzung von "packed"-Struckturen, die mir über 
eine Library mit reingekommen sind. Also offenbar kann es "der Compiler" 
wohl nicht (um es klar zu machen: Ich meine damit, dass die Menge der 
Compiler, die das nicht können, >0 ist).

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Stimmt es etwa nicht, dass
> nicht jede CPU problemlos auf Datentypen mit falschem Alignment
> zugreifen kann?

Ja. Für eine gepackte Strukturen stimmt das nicht.
In einer gepackten Struktur kann die CPU problemlos auf Elemente mit 
falschem Alignment zugreifen, weil der Compiler das garantiert und 
entsprechenden Code generiert.

Du behauptest weiterhin, dass das anders ist. Du liegst leider falsch.

von mh (Gast)


Lesenswert?

MaWin schrieb:
> mh schrieb:
>> Wie soll man das anders interpretieren
>
> Indem man das gesamte Gespräch liest, und nicht nur den Teil, der extra
> so herausgepickt wurde, um mich dumm dastehen zu lassen.
Ich habe deinen Vollständigen Beitrag zitiert. Wenn sich deine Antwort 
in diesem Beitrag auf mehr als den einen dort von dir zitierten Satz 
bezieht, solltest du mehr zitieren.

> Antworten bedingen immer, dass man die beantworteten Texte auch liest.
> Und zwar alle relevanten, rekursiv.
Wenn das auf deine Beiträge zutrifft, solltest du das dazu schreiben. 
Vor allem, was du für RELEVANT hälst. Nur so als Tipp: Du könntest 
z.B. zitieren, was du für relevant hälst.

von MaWin (Gast)


Lesenswert?

mh schrieb:
> solltest du mehr zitieren.

Nur keinen Fehler zugeben wollen, gell? Du könntest Rolf sein.

von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Rolf M. schrieb:
>> Stimmt es etwa nicht, dass
>> nicht jede CPU problemlos auf Datentypen mit falschem Alignment
>> zugreifen kann?
>
> Ja. Für eine gepackte Strukturen stimmt das nicht.
> In einer gepackten Struktur kann die CPU problemlos auf Elemente mit
> falschem Alignment zugreifen, weil der Compiler das garantiert und
> entsprechenden Code generiert.

Der Compiler baut in diesem Fall den Code so um, dass die CPU keine 
Zugriffe mit falschem Alignment mehr ausführt.

> Du behauptest weiterhin, dass das anders ist. Du liegst leider falsch.

Ich denke, wir haben da einfach eine unterschiedliche Betrachtungsweise. 
Du betrachtest es von der abstrakten Sprachebene aus (wo das aber nicht 
standardisiert ist, sondern eben gänzlich vom verwendeten Compiler 
abhängt), ich aus Sicht der CPU selbst und welche Speicherzugriffe sie 
tatsächlich ausführt.
Um ersteres kann sich der Compiler in gewissen Grenzen und mit 
entsprechenden Nachteilen bei Codegröße und Laufzeit kümmern, letzteres 
ist einfach eine Gegebenheit.
Aber von mir aus können wir uns einigen auf ein: "Die CPU kann es von 
sich aus nicht, aber der Compiler kann eine entsprechende Krücke 
einbauen, um diese Einschränkung zum umgehen".

MaWin schrieb:
> Nur keinen Fehler zugeben wollen, gell? Du könntest Rolf sein.

Ich kann Fehler durchaus zugeben, wenn ich denn welche gemacht hab und 
habe das hier im Forum auch schon öfters getan.

von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Aber von mir aus können wir uns einigen auf ein: "Die CPU kann es von
> sich aus nicht, aber der Compiler kann eine entsprechende Krücke
> einbauen, um diese Einschränkung zum umgehen".

Genau. Und der Mechanismus "entsprechende Krücke" nennt sich packed 
struct.
Somit kann bei einer packed struct kein "Problem beim Zugriff", oder wie 
du es auch immer formulieren willst, auftreten. Darum ging es ja nur. Es 
gibt kein "Problem beim Zugriff".

von c-hater (Gast)


Lesenswert?

MaWin schrieb:

> Somit kann bei einer packed struct kein "Problem beim Zugriff", oder wie
> du es auch immer formulieren willst, auftreten.

Doch, natürlich kann ein Problem auftreten. Das Herumwirtschaften um die 
Gegebenheiten der Hardware löst zwar das Problem der Möglichkeit des 
Zugriffs, dies aber natürlich auf Kosten der Zugriffszeit.

Und auch das kann natürlich ein Problem sein bzw. werden.

von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> Das Herumwirtschaften um die
> Gegebenheiten der Hardware löst zwar das Problem der Möglichkeit des
> Zugriffs, dies aber natürlich auf Kosten der Zugriffszeit.

Dann bin ich ja mal gespannt, wie du das besser machen willst.
Zeig doch mal konkret.

von c-hater (Gast)


Lesenswert?

MaWin schrieb:

> Dann bin ich ja mal gespannt, wie du das besser machen willst.

Indem ich eine Sprache verwende, die eine feingranulare 
Eingriffsmöglichkeit auf die Speicherorganisation von Strukturen von 
Haus aus anbietet (oder zumindest ermöglicht) und nicht dieses 
unsägliche C.

Der Witz ist: es gibt viele solche Sprachen. Deine idiotische Fixierung 
auf diesen unsäglich schlechten Macroassembler namens C nimmt dir die 
Sicht darauf. Am C-Tellerrand ist für dich halt Ende Gelände.

von Hugo (Gast)


Lesenswert?

Hast wieder Freigang heute? Dein Gesabbel wird immer schlimmer.

von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> Indem ich eine Sprache verwende, die eine feingranulare
> Eingriffsmöglichkeit auf die Speicherorganisation von Strukturen von
> Haus aus anbietet

Dann kannst du ja einmal ein Beispiel machen.

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> Indem ich eine Sprache verwende, die eine feingranulare
> Eingriffsmöglichkeit auf die Speicherorganisation von Strukturen von
> Haus aus anbietet

Also Bitfelder in C. Feingranularer geht nicht. ;-)

von c-hater (Gast)


Lesenswert?

MaWin schrieb:

> Dann kannst du ja einmal ein Beispiel machen.

Dot.Net z.B. stellt erschöpfende Möglichkeiten dafür bereit (natürlich 
in jeder Dot.Net-Sprache, nur halt mit leicht variierender Syntax).

Das gibt es als Hauptsache ein StructLayout-Attribut mit den 
Hauptparametern LayoutKind und Pack und und im Extremfall Attribute für 
die Steuerung der Ausrichtung jedes einzelnen Feldes (für Strukturen mit 
LayoutKind.Explizit).

von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> Dot.Net z.B. stellt erschöpfende Möglichkeiten dafür bereit

Das ist ja nett.
Und dann kannst du uns auch bestimmt zeigen, wo das den enormen Vorteil 
bei der Ausführungsgeschwindigkeit gegenüber C bietet.

Kleiner Tipp: Auch damit kann die CPU ein unaligned-Feld nicht als 
Ganzes lesen.

Gegen angebliche Performanceprobleme bei C dann DotNet vorzuschlagen, 
hat schon etwas ulkiges.

Im Gegensatz zu deiner Annahme bin ich kein C-Jünger. Ich bin aber auch 
kein C-Hater.

von W.S. (Gast)


Lesenswert?

Oliver S. schrieb:
> Das die stdint.h-Datentypen keine systemübergreifende Kompatibilität
> beim Datenaustausch bieten, und auch nie dafür gedacht waren, dürfte so
> ziemlich jedem klar sein. Nur dir nicht.

O danke für die Blumen, du Kurzsichtiger.

Der eigentliche Anlaß war, daß es in C keine wirklich sauberen 
Definitionen für Integer-Größen gibt. Lediglich einige gummiweiche 
Ansagen, daß z.B. int mindestens 16 Bit breit sein soll. Ich kann ja 
verstehen, daß man in den allerersten Anfangszeiten der ganzen 
Mikrorechnerei sich diverse Optionen offenhalten wollte, aber sowas wird 
nach rund 40 Jahren immer mehr zur Bürde. Also stand eigentlich ein ganz 
kleines Renovieren von C an, dahingehend, daß die C-Programmierer 
Integer-Datenbreiten haben wollen, auf die sie sich verlassen können. 
Also (wieder zum Beispiel) "int ist GENAU 16 Bit breit" oder so.

Aber zu so einer weltbewegenden Neuerung konnte man sich nicht 
durchringen, weswegen der Berg zwar gekreißt hat, aber nur einen 
Vorschlag zu einer Headerdatei dabei gebar, die bittesehr ein jeder 
Hersteller auf seine Produkte anpassen möge, damit (wieder z.B.) bei int 
auch wirklich 16 Bit herauskommen möge. Es ist zwar lächerlich und 
bietet keinerlei Fortschritt, aber es war ohne jegliche Änderung an den 
Compilern machbar.

Das Ärgerliche daran ist, daß es derart in Mode gekommen ist, daß viele 
Programmierer meinen, in C jetzt echte neue Integertypen zu haben und 
die Gedankenlosigkeit geht so weit, daß selbst für Textzeichen uint8_t 
verwendet werden. Als ob ein String "Ottokar" zum Integer-Rechnen 
gedacht sei.

Und eben dieselben Leute meinen, daß dieses zum Sicherstellen der 
Kompatibilität da sei. Also wenn jemand besagten 'Ottokar' in einige 
char packt, gibt es Kompatibilitätsprobleme, bei uint8_t jedoch nicht. 
Ich hab da so den Eindruck, daß die Menschheit zu allen Zeiten ein 
gewisses Maß an Aberglauben für ihr Seelenheil braucht. Und um zu 
zeigen, daß man bereits bei einer Plattform mit anderer Endianess eine 
Bauchlandung macht, auch wenn man alle seine Variablen brav nach der 
neuesten Mode deklariert hat, ist die Diskussion über Endianess 
aufgekommen.

Dem Mathematiker ist es klar: sobald man eine Theorie auch nur in einem 
einzigen Fall widerlegt hat, ist sie insgesamt widerlegt. So auch eben 
das ganze Geschwurbel über all diese xintyy_t und die besagte 
Headerdatei. Richtig ist, daß man sich als Programmierer SELBST 
Gedanken machen muß, was für Integerbreiten für eine bestimmte Aufgabe 
am ehensten geeignet sind, was ja eben auch das Thema dieses Threads 
ist: "Möglichst viel uint8_t verwenden?". Da sucht jemand, der offenbar 
orientierungslos ist, nach einem Geländer, das ihn auf den rechten Weg 
geleiten soll. Und zwar möglichst ohne daß er selbst drüber nachdenken 
muß

W.S.

von MaWin (Gast)


Lesenswert?

W.S. schrieb:
> Der eigentliche Anlaß war

Du musst weniger, oder mehr nehmen. Egal was. Die Menge stimmt nicht.

von Äh (Gast)


Lesenswert?

Erwin schrieb:
> Franz schrieb:
>
>> Bei einem 32-Bit-Mikrocontroller, wie z.B. dem
>> ESP32, ist ja nach wie vor der RAM oft das Problem, wenn Projekte
>> umfangreich werden.
>
> Programmieren lernen hilft wohl am besten ...

Micropython ist doch so grossartig und die Zukunft. /s

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> weswegen der Berg zwar gekreißt hat, aber nur einen
> Vorschlag zu einer Headerdatei dabei gebar

NB: Das ist kein Vorschlag, sondern Teil des Sprachstandards. Ob man 
etwas im Code des Compilers festlegt, oder in einem Headerfile, ist 
höchstens für Sprachpuristen von Bedeutung, denen der Compiler nicht 
gross genug sein kann.

Man hätte eine völlig neue Sprache definieren können, die alle bekannten 
Fehler rauswirft. Dann hätten einige Dutzend Leute die neue Sprache 
verwendet, die zu bestehendem Code inkompatibel ist, und der grosse Rest 
hätte weiterhin das alte hässliche C verwendet.

Und weil dieser Effekt schon vorher bekannt war, hat das Gremium sich 
entschlossen, das alte hässliche C ohne Verlust von Kompatibilität 
weiterzuentwickeln. Das war deren Zuständigkeit. Und man überliess es 
anderen Sprachschöpfern und Gremien, neue Sprachen zu definieren, die 
alles richtig machen.

Der Rest ist die Freiheit des Anwenders, sich das Genehme auszusuchen. 
So lange die Leute aber an C hängen, wie die Alkis an der Flasche, so 
lange wird ein Gremium benötigt, dass C behandelt. Und so lange werden 
diese Alkis sich in Foren lauthals darüber beklagen, dass sie von der 
Welt dazu gezwungen werden.

: Bearbeitet durch User
von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

(prx) A. K. schrieb:
> Und so lange werden
> diese Alkis sich in Foren lauthals darüber beklagen, dass sie von der
> Welt dazu gezwungen werden.

Ist das jetzt die Schlange , die sich selber in den Schwanz beißt?
---GRINS....

von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> Der eigentliche Anlaß war, daß es in C keine wirklich sauberen
> Definitionen für Integer-Größen gibt. Lediglich einige gummiweiche
> Ansagen, daß z.B. int mindestens 16 Bit breit sein soll.

Ja. Ist seit Erfindung der Sprache so, und wird sich auch nie ändern.

Lebe damit, oder nimm eine andere Programmiersprache. Sich in jedem 
zweiten Beitrag zum Thema drüber aufzuregen ist kindisch.

Nicht akzeptieren zu wollen, daß die stdint-Datentypen auch Teil des 
C-Standards sind, ist genauso kindisch. Aber das alles ist ja nun schon 
hundertfach mit dir durchgekaut worden.

Oliver

von W.S. (Gast)


Lesenswert?

(prx) A. K. schrieb:
> NB: Das ist kein Vorschlag, sondern Teil des Sprachstandards. Ob man
> etwas im Code des Compilers festlegt, oder in einem Headerfile, ist
> höchstens für Sprachpuristen von Bedeutung,

Das ist in sich widersinnig - allerdings kommt es der Überschrift dieses 
Threads durchaus nahe: Laßt uns alles Rechnen in unsigned char 
erledigen, dann kann man den Compiler vereinfachen und all die 
Überträge, Vorzeichenbehandlung usw. in einer in C geschriebenen 
Bibliothek erledigen. Das würde sogar die Sache mit der Endianess 
erledigen und wozu braucht man eigentlich 32 Bit Controller?

Nein, das wäre das Tollhaus.

Unterschiedliche Datenbreiten gebrauchen auch unterschiedliche 
Maschinenbefehle und das richtig zu übersetzen ist Obliegenkeit des 
Compilers. Es ist also der Compiler UND SONST KEINER, der einen 
bestimmten Datentyp kennen und in passende Maschinenoperationen 
übersetzen muß. Punkt.

Dabei ist es vollständig schnurz, ob jemand eine Headerdatei zum 
Sprachstandard hinzuzählt oder nicht.

W.S.

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> Es ist also der Compiler UND SONST KEINER, der einen
> bestimmten Datentyp kennen und in passende Maschinenoperationen
> übersetzen muß. Punkt.

Genau das tut er auch dann, wenn der Autor des Compilers es vorzog, 
einen Typedef wie uint8_t in ein Headerfile zu schreiben, statt direkt 
in den Quellcode des Compilers. Das ist gleichwertig.

> ob jemand eine Headerdatei zum
> Sprachstandard hinzuzählt oder nicht.

Wenn für dich nur das Verhalten des EXE-Files zählt, nicht aber der 
Sprachstandard, ist das kein Problem der Sprache, sondern eines von dir 
persönlich. Solche Header sind fester Teil der Compiler-Suite und der 
Inhalt ist per ISO-Dokument vorgeschrieben.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> Es ist also der Compiler UND SONST KEINER, der einen
> bestimmten Datentyp kennen und in passende Maschinenoperationen
> übersetzen muß. Punkt.

Die Forderung ist so selbstverständlich, daß man das nicht groß erwähnen 
muß. Und, auch wenn es dich vielleicht überrascht: Jeder C-Compiler 
kennt alle seine ihm bekannten Datentypen und übersetzt die in passende 
Maschinenoperationen.

Dein "UND SONST KEINER" ist trotzdem grundfalsch. Derjenige, der den 
Compiler benutzt, muß die Datentypen genauso gut kennen. Was einen dann 
über ein paar weitere und durchaus sinnvolle Gedankenschritte zur 
stdint.h bringt.

Oliver

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Oliver S. schrieb:
> Jeder C-Compiler
> kennt alle seine ihm bekannten Datentypen und übersetzt die in passende
> Maschinenoperationen.

Tja und das sind char, int und float mit diversen Attributen wie signed, 
long, double usw.
Siehste.

W.S.

von MaWin (Gast)


Lesenswert?

W.S. schrieb:
> Nein, das wäre das Tollhaus.

Es ist sehr lustig zu lesen, wie du deine kruden Theorien immer 
weiterentwickelst, nur um Recht behalten zu können.

Inhaltlich diskutiere ich mit dir natürlich nicht mehr, weil das Thema 
bereits erschöpfend behandelt wurde.

Aber mache du bitte weiter. Es amüsiert mich sehr.

von DerEgon (Gast)


Lesenswert?

W.S. schrieb:
> Tja und das sind char, int und float mit diversen Attributen wie signed,
> long, double usw.
> Siehste.

Wenn Du als einzig gültige Sprachdefinition von C die von C89 
akzeptierst, dann ja.

In neueren C-Standards (ab C99) gehört aber stdint.h und das, was da 
drinsteht, zum Sprachumfang.

Siehste.

von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> Tja und das sind char, int und float mit diversen Attributen wie signed,
> long, double usw.
> Siehste.

Und wenn du jetzt einen 16 bit signed int brauchst, welche nimmst du nun 
davon?

Ich nehme da einen int16_t. Das "typedeft" dann die 
implementationsspezifische stdint.h auf den passenden Typ des Compilers 
(short, int, ...), und alle haben, was sie brauchen.

Siehste. So einfach kann das Leben sein.

Oliver

von (prx) A. K. (prx)


Lesenswert?

Oliver S. schrieb:
> und alle haben, was sie brauchen.

Fast alle. Klar ist, dass ihm nicht reicht, wenn es funktioniert, 
sondern es muss auch auf genau seine Art funktionieren. Auch wenn wir 
bisher nicht wissen, wie die aussieht.

Ich erinnere mich vage, dass Ada in dieser Richtung einige Möglichkeiten 
hat. Ada wurde ja u.A. für eine einheitliche Entwicklung von 
Steuerungssystemen definiert.

PS: Bis hin zur Bitorder: "For record subtypes, GNAT permits the 
specification of the Bit_Order attribute."
https://docs.adacore.com/gnat_rm-docs/html/gnat_rm/gnat_rm/representation_clauses_and_pragmas.html

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

PPS: Kennt hier jemand jemanden, der jemanden kennt, der Ada nutzt?

von W.S. (Gast)


Lesenswert?

Oliver S. schrieb:
> Und wenn du jetzt einen 16 bit signed int brauchst, welche nimmst du nun
> davon?

Bei einem 32 Bit µC? Da nehme ich für was Lokales einen long. Kommt ja 
auf den Stack. Fertig. Ansonsten einfach einen int - und zwar ohne Umweg 
über irgendwelche Headerfiles.

Ich schrieb ja schon, daß diese letzte Marotte nichts Neues gebracht 
hat. Bei dem typischen Wildwuchs a la U32, U16, U8 und so war klar zu 
erkennen, daß dies der Bequemlichkeit der Schreiber diente, schließlich 
ist U32 viel kürzer als unsigned long int und den typischen C 
Programmierern ist jedes Textzeichen eigentlich schon zuviel.

W.S.

von Hans W. (Firma: Wilhelm.Consulting) (hans-)


Lesenswert?

Dann werf ich noch mal folgendes in den Raum:
1
uint_fast8_t
1
uint_least8_t

Mit den *_fast*_t typen bekommst du immer den schnellsten Datentyp der 
dir mindestens 8,16,32 oder 64bit liefert.

Auf einer typischen 32bit architektur wären das dann 32bit für den 
uint_fast8_t.

Achja, du kannst ggf. gewaltig code sparen und Geschwindigkeit gewinnen, 
wenn du Globale in strukturen/klassen legst.

Wenn deine Zielarchitektur indirekte Addressierung kann (z.B. der Arm 
Corex), dann braucht der dann nur 1x die Basisadresse laden und holt 
sich dann die Daten passend von dort. Das funktioniert dann ähnlich wie 
vom Stack.

8bit Architekturen sind etwas eigen, da C 16bit integer erwartet. Aber 
ab einer 16bit Architektur macht es absolut keinen Sinn über Datentypen 
zu sinnieren. Solange "dein" int groß genug ist (also je nach 
Architektur) ist das normalerweise das effektivste, da üblicherweise 
Datenbusse, Register, Befehlsatz, ... auf diese Größe ausgelegt sind.

73

von c-hater (Gast)


Lesenswert?

MaWin schrieb:

> Kleiner Tipp: Auch damit kann die CPU ein unaligned-Feld nicht als
> Ganzes lesen.

Natürlich nicht. Aber ich HABE DIE MACHT, es auch in einer weitgehend 
"packed" organisierten Struktur korrekt zu alignen. Wenn es halt wichtig 
genug ist, um die Abweichung vom allgemeinen Ziel der Speicherersparnis 
für diese Struktur in genau diesem einen Punkt aufzuweichen.

Dem Programmierer gehört die Macht, nicht irgendeinem verschissenen 
Compiler. Und schon garnicht den strukturell (durch die Sprache selber) 
massiv behinderten C-Compilern.

von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> Aber ich HABE DIE MACHT

Diese C-Hasserei ist schon ziemlich krankhaft bei dir, meinst du nicht?

von c-hater (Gast)


Lesenswert?

MaWin schrieb:

> Diese C-Hasserei ist schon ziemlich krankhaft bei dir, meinst du nicht?

Aha, rein garnix zu den unbestreitbaren Fakten...

Kann es sein, dass vielmehr deine Verteidigung von C einigermaßen 
krankhaft ist? Hast du da mal drüber nachgedacht?

von Wissender (Gast)


Lesenswert?

W.S. schrieb:

> Ich schrieb ja schon, daß diese letzte Marotte nichts Neues gebracht
> hat. Bei dem typischen Wildwuchs a la U32, U16, U8 und so war klar zu
> erkennen, daß dies der Bequemlichkeit der Schreiber diente, schließlich
> ist U32 viel kürzer als unsigned long int und den typischen C
> Programmierern ist jedes Textzeichen eigentlich schon zuviel.
>
> W.S.

Du hast absolut keine Ahnung von Datentypen. Das wird immer 
offensichtlicher.
int, long usw. sind Architekturabhängig.
uint8_t, uint16, uint32_t usw. sind immer so breit wie der Bezeichner 
aussagt. Das könntest du mit sizeof() selbst auf verschiedenen 
Plattformen ausprobieren. Mach es einfach bevor du dich weiter 
blamierst.

von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> Aha, rein garnix zu den unbestreitbaren Fakten...

Warum auch. Du hast Recht.
Ich hingegen meine nur, dass es keine Rolle spielt, wie C packed structs 
genau implementiert.

> Kann es sein, dass vielmehr deine Verteidigung von C einigermaßen
> krankhaft ist?

Wie ich bereits schrieb: Ich verteidige C keineswegs. Wozu auch. C ist 
eine ziemlich schlechte Sprache.
Trotzdem nutze ich sie, wo es Sinn ergibt. Und dort nutze ich auch 
packed structs. Die angeblichen Performanceprobleme, die es deiner 
Meinung nach dabei geben soll, sind mir noch nie untergekommen. Die 
angeblichen Performanceverluste sind in realen Programmen kaum vorhanden 
und praktisch nicht relevant.

von (prx) A. K. (prx)


Lesenswert?

MaWin schrieb:
> Trotzdem nutze ich sie, wo es Sinn ergibt. Und dort nutze ich auch
> packed structs. Die angeblichen Performanceprobleme, die es deiner
> Meinung nach dabei geben soll, sind mir noch nie untergekommen.

Das hängt einerseits von der Plattform ab, inwieweit misaligned access 
erlaubt ist, oder zum Absturz führt und daher vom Compiler ersetzt 
werden müssen.

Wenn deine Szenarien freilich mehr im Controller-Sektor liegen, treten 
manche Gründe für Performance-Einbrüche nicht in Erscheinung. So können 
bei Highend-Prozessoren (sowas wie in PC und Smartphone) und einem Mix 
aus Lesen- und Schreiboperationen auf der Ebene der Mikroarchitektur 
böse Einbrüche auftreten. Und zwar auch dann, wenn die CPU das kann.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

MaWin schrieb:

> C ist
> eine ziemlich schlechte Sprache.

Nicht mehr und nicht weniger sage ich immer und immer wieder. Will nur 
niemand hören. Wird sogar als "krankhaft" eingestuft, das zu sagen. So 
auch von dir, nur wenige Postings höher...

Wer ist hier krank?

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> sage ich immer und immer wieder.

Es gibt neben dem, was man zu sagen meint, auch das, was andere dabei 
wahrnehmen, und wie man es sagt. Und ganz besonders fällt dabei eine 
gewisse Penetranz auf.

von Mombert H. (mh_mh)


Lesenswert?

(prx) A. K. schrieb:
> c-hater schrieb:
>> sage ich immer und immer wieder.
>
> Es gibt neben dem, was man zu sagen meint, auch das, was andere dabei
> wahrnehmen, und wie man es sagt. Und ganz besonders fällt dabei eine
> gewisse Penetranz auf.
Vor allem dann, wenn jedes mal "*c-hater* schrieb" drüber steht ;-)

von c-hater (Gast)


Lesenswert?

(prx) A. K. schrieb:

> Und ganz besonders fällt dabei eine
> gewisse Penetranz auf.

Hihi. Genau so wie mir die Penetranz der C-Apologeten auffällt,, die 
halt mit unglaublicher Zähigkeit immer und immer wieder behaupten, dass 
C alle Probleme löst und die C-Compiler so tierisch gut sind, dass sie 
immer besseren Code liefern als der beste Mensch das könnte.

Diese überaus penetranten Lügen waren der Anlass zur Geburt des 
"c-hater" und bis heute haben diese Lügen nicht nachgelassen, und 
erhalten somit auch den "c-hater" unendlich am Leben...

Usache->Wirkung. So einfach ist das.

von Mombert H. (mh_mh)


Lesenswert?

c-hater schrieb:
> Diese überaus penetranten Lügen waren der Anlass zur Geburt des
> "c-hater" und bis heute haben diese Lügen nicht nachgelassen, und
> erhalten somit auch den "c-hater" unendlich am Leben...
Das klingt in der Tat etwas krankhaft.

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> Hihi. Genau so wie mir die Penetranz der C-Apologeten auffällt,

Es gibt neben mir eine Menge Leute, die zu C jene Ambivalenz pflegen, 
wie sie auch in diesem Beitrag ausgedrückt wird:
Beitrag "Re: 32-Bit-µC: Möglichst viel uint8_t verwenden?"

Man kann C verwenden und damit zurecht kommen, ohne es zu mögen. Deinen 
Apologeten begegne ich weit seltener als Pragmatikern. Jenen, die es 
kennen und nutzen, ohne davon so begeistert zu sein, wie du suggerierst.

> die C-Compiler so tierisch gut sind

Hier beziehst du dich auf Assembler vs Compiler Diskussionen, die vor 
einigen Jahren recht heftig abliefen und einen Teilnehmer so in Rage 
brachten, dass er aus dem Forum flog.

Allerdings war darin zwar C jene Sprache, die in der Diskussion gegen 
Assembler stand. Grundsätzlich waren C Compiler darin aber nur 
Platzhalter für Compiler allgemein. Es ging um die Alternative zwischen 
Assembler und jedweder Art von Compiler, nicht speziell um C.

In diesem Thread geht es jedoch nicht um Assembler gegen Compiler 
allgemein, sondern um bestimmte Eigenschaften der Sprache C.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Die Kritik an der schwachen Definition der C Typen begleitete C schon 
früh, und führte auch zu einem jener seltenen Fälle, in denen 
bestehender Code gebrochen wurde. Nämlich beim Thema sign- vs 
value-preserving, was aus K&R nicht eindeutig hervorging und deshalb 
verschieden implementiert wurde. ANSI C legte das fest.

C wurde nie als 1000-jährige Sprache erfunden, sondern für einfache 
Compiler auf ressourcenarmen Minicomputern der Entstehungszeit. Wer von 
12-Pass Compilern damaliger Mainframes gehört hat, kann sich vielleicht 
vorstellen, was ich meine. Aufgrund des Erfolgs von Unix im Kontext von 
Universitäten nahm die Verbreitung und Kenntnis zu. Die relativ geringe 
Komplexität von C Compilern führte dann auch dazu, dass sie für 
Mikrocontroller genutzt wurden. Es war kein Lebenswerk, einen Compiler 
zu bauen. Zum Vergleich: Der erste Ada Compiler galt als abschreckender 
Moloch, der schon allein dadurch die Verbreitung der Sprache behinderte.

Das war von Anfang bis heute kein ideologischer Ansatz, sondern ein rein 
pragmatischer. Man brauchte was, man hatte oder kannte was, man nutzte 
es. Die meisten Leute schaffen das allerdings, ohne sich täglich darüber 
öffentlich zu ergiessen, wie schlecht ihre Werkzeuge doch wären.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> dass C alle Probleme löst und die C-Compiler so tierisch gut sind

Dir wird sicher auffallen, dass niemand ebensolche Behauptungen in 
diesem Thread getroffen hat.

Ich kenne nur einen, der (alleine schon mit seinem Nick) herumhetzt. Es 
ist der C-Hater.

von Hans W. (Firma: Wilhelm.Consulting) (hans-)


Lesenswert?

(prx) A. K. schrieb:
> MaWin schrieb:
>> Trotzdem nutze ich sie, wo es Sinn ergibt. Und dort nutze ich auch
>> packed structs. Die angeblichen Performanceprobleme, die es deiner
>> Meinung nach dabei geben soll, sind mir noch nie untergekommen.
>
> Das hängt einerseits von der Plattform ab, inwieweit misaligned access
> erlaubt ist, oder zum Absturz führt und daher vom Compiler ersetzt
> werden müssen.

Ich sage nur SIMD Befehle auf x86... da willst du sogar deine daten auf 
cachelines ausrichten.
Oder unaligned access auf ARM7, ARM9, Cortex-M0... die schmieren einfach 
ab, wenn du das machen würdes.

Am Cortex-m3 geht unaligned-access grundsätzlich - es gibt aber einen 
"penalty-cycle".

73

von (prx) A. K. (prx)


Lesenswert?

Hans W. schrieb:
> Am Cortex-m3 geht unaligned-access grundsätzlich - es gibt aber einen
> "penalty-cycle".

Ja, ein einzelner Straftakt ist aber der harmlose Teil. Übler wird es 
bei Out-Of-Order Cores, wenn ein Load auf einen Store folgt, der nicht 
vom Store Buffer bedient werden kann (=> store to load forwarding). 
Sowas gibts beispielsweise bereits bei einem Byte-Store und 
nachfolgendem Word-Load von der gleichen Adresse. Das kann zweistellige 
Takte kosten und kann bei Misalignment leicht auftreten.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Hans W. schrieb:
> Ich sage nur SIMD Befehle auf x86... da willst du sogar deine daten auf
> cachelines ausrichten.

SSE hat eigens ein paar Befehle, um bei Misalignment gepflegt auf die 
Schnauze fliegen zu dürfen. Sowas wie MOVDQA (aligned) vs MOVDQU 
(unaligned).

Und bei AVX-512 ist der Unterschied zwischen der Grösse der Daten und 
der Grösse der Cachelines ohnehin nicht mehr arg gross.

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

Hans W. schrieb:
> Am Cortex-m3 geht unaligned-access grundsätzlich - es gibt aber einen
> "penalty-cycle".

Nein. Nicht in Strictly Ordered oder Device Memory getaggten 
Speicherbereichen. Z.b. im I/O Speicher der Peripherien.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Der eigentliche Anlaß war, daß es in C keine wirklich sauberen
> Definitionen für Integer-Größen gibt.

Genau das ist eine der wesentlichen Stärken von C.

Nur so war und ist es möglich, eine C-Standard-Lib bereitzustellen, die 
auf allen Architekturen - angefangen vom Z80 bis zum Supercomputer in 
den Top-10 - portabel und mit der für den Host optimalen Performance 
läuft.

Es wurde nämlich (meist) darauf geachtet, dass ein Integer der 
"natürlichen Bitbreite" der verwendeten CPU entspricht. Das ist ein 
Vorteil sondergleichen. Hätte man damals den Integer als 16-Bit 
festgetackert, würden C-Programme heute auf 32- oder 64-Bit Systemen 
grottenlahm laufen, weil sie mit einer solchen Altlast nicht optimal 
arbeiten können. Die meisten C-Standard-Funktionen arbeiten mit Integern 
und Pointern, die eben nicht in der Bitbreite festgelegt sind. Und das 
ist auch gut so. denn sie arbeiten mit denjenigen Typen, mit denen sie 
optimal umgehen können.

So laufen auch heute noch Programme aus den 80ern ohne Code-Änderung, 
welche auf 64-Bit-Systemen ganz normal mit mehreren GB großen Dateien 
umgehen können. Wäre damals ein Integer auf 16 Bit festgetackert worden, 
hätte man die alle umschreiben müssen.

Du hast Probleme mit der C-Standard-Lib, weil Du diese als nicht zum 
C-Sprachumpfang gehörend betrachtest. Deshalb ignorierst Du auch 
stdint.h und die damit verbundenen Typen uint8_t, uint16_t usw. Doch das 
ist ein Irrtum. Ohne C-Standard-Lib hast Du gar nichts, noch nichtmals 
stdio.h.

Wenn Du stdint.h ablehnst, dann sei wenigstens so konsequent und mache 
auch um die stdio.h, string.h und alle weiteren einen großen Bogen. 
Schon mal putchar() oder strlen() verwendet? Warum? Schreibs Dir doch 
selber, so wie Du das auch mit U8, U16 usw. machst und auch noch 
predigst! Lächerlich ist dabei, dass Du für jeden Host (Target) Deine 
eigens definierten Typen immer wieder anpassen musst. Damit führst Du 
Deine Argumentation doch ad absurdum.

Ein include von stdint.h reicht. Dann hast Du Deine festgetackerten 
Typen. Und ja, ohne die Includes der C-Standard-Lib kann man nicht 
arbeiten - auch Du nicht.

P.S.

Wo Du doch so ein Pascal-Fan bist:

Auszug aus https://wiki.freepascal.org/Integer :

The size of an integer is dependent upon the bit size of the target 
machine to which the compiler is to generate code (32 bit or 64 bit), 
the type of compiler (16-bit, 32-bit or 64-bit), and upon compiler 
switches in some cases.

Ohne die flexible Definition hätte Pascal (und deren Nachfolger 
Modula-2/Oberon) nicht überleben können, sondern wären allesamt 
vorzeitig gestorben.

: Bearbeitet durch Moderator
von Mombert H. (mh_mh)


Lesenswert?

Frank M. schrieb:
> Es wurde nämlich (meist) darauf geachtet, dass ein Integer der
> "natürlichen Bitbreite" der verwendeten CPU entspricht. Das ist ein
> Vorteil sondergleichen. Hätte man damals den Integer als 16-Bit
> festgetackert, würden C-Programme heute auf 32- oder 64-Bit Systemen
> grottenlahm laufen, weil sie mit einer solchen Altlast nicht optimal
> arbeiten können. Die meisten C-Standard-Funktionen arbeiten mit Integern
> und Pointern, die eben nicht in der Bitbreite festgelegt sind. Und das
> ist auch gut so.

Stell dir vor, jemand hätte size_t auf 16 Bit festgenagelt :-)

von W.S. (Gast)


Lesenswert?

Wissender schrieb:
> int, long usw. sind Architekturabhängig.

Ja eben. Genau DAS war es, was ich genannt habe. Und alle Alias, die 
in irgendeiner Headerdatei erzeugt werden, wären per se eben genauso 
abhängig. Eben deshalb wird es den Toolherstellern oder sonstigen 
Zulieferern anheimgestellt, besagte Headerdateien so zu schreiben, daß 
das Gewünschte dabei herauskommt.

> uint8_t, uint16, uint32_t usw. sind immer so breit wie der Bezeichner
> aussagt.

Und das kommt daher, daß sie nur ein Alias des jeweils passenden 
Grundtyps sind, hingeschrieben von einem Zulieferer.

W.S.

von W.S. (Gast)


Lesenswert?

Frank M. schrieb:
> Genau das ist eine der wesentlichen Stärken von C.

Andere haben sowas bereits treffend formuliert: "It's not a bug, it's a 
feature"

Frank M. schrieb:
> Hätte man damals den Integer als 16-Bit
> festgetackert, würden C-Programme heute auf 32- oder 64-Bit Systemen
> grottenlahm laufen, weil sie mit einer solchen Altlast nicht optimal
> arbeiten können.

Erzähle nicht solchen Unsinn. Das ist etwas, was du dir selbst aus den 
Fingern gesaugt hast. Hätte man damals den int auf 16 Bit festgetackert 
und den long int auf 32 Bit und den (später dazugekommenen) long long 
int auf 64 Bit, dann würden heutige C Programme auch nicht langsamer 
laufen.

Was du vermutlich sagen willst: "Wenn man alte Quellcodes ohne jegliche 
Änderung für Maschinen übersetzen will, die Probleme mit 16 Bit Integers 
haben, dann wird's langsam." Aber das hängt nicht daran, daß man nicht 
Rechenoperationen, für die 16 Bit ausreichend sind, auf Maschinen mit 32 
oder 64 Bit Rechenbreite nicht ausführen könnte - oh nein, sowas hängt 
eigentlich immer an irgendwelchen Tricks mit Überläufen, Typecasts 
usw., die ein besonders schlauer C-Programmierer benutzt hat.

So ist (und war) das.

Frank M. schrieb:
> Wenn Du stdint.h ablehnst, dann sei wenigstens so konsequent und mache
> auch um die stdio.h, string.h und alle weiteren einen großen Bogen.
> Schon mal putchar() oder strlen() verwendet? Warum? Schreibs Dir doch
> selber, so wie Du das auch mit U8, U16 usw. machst und auch noch
> predigst!

Um das Reizwort auch hier mal wieder zu nennen: Du hast offensichtlich 
nicht in die Quellen zur Lernbetty geschaut.
Und was solche Bezeichner wie U8, U16 usw. betrifft: Das haben Andere 
benutzt. Tu also nicht so, als ob das auf meinem Mist gewachsen wäre. 
Jetzt hast du nun eine ellenlange Epistel mit ganz offensichtlich 
falschen Unterstellungen geschrieben. Warum? Bloß um zu stänkern?


So, zurück zum Thema.
Die Überlegung, auf 32 Bit Maschinen "Möglichst viel uint8_t verwenden" 
zu wollen um nicht so viel RAM zu verbrauchen ist verkehrt. Besser ist 
allemal, sich Gedanken um bessere Algorithmen zu machen und die 
Datenbreite von Integers nicht gedankenlos zu wählen.

W.S.

von MaWin (Gast)


Lesenswert?

Frank M. schrieb:
> Nur so war und ist es möglich, eine C-Standard-Lib bereitzustellen, die
> auf allen Architekturen - angefangen vom Z80 bis zum Supercomputer in
> den Top-10 - portabel und mit der für den Host optimalen Performance
> läuft.

Dafür braucht man aber nicht das ganze Typsystem zu verkrüppeln, sondern 
es reicht, wenn man einen Typ anbietet, der der nativen Breite 
entspricht.

Das als "Genau das ist eine der wesentlichen Stärken von C." ist schon 
etwas überzogen. Rust löst das wesentlich besser.

> So laufen auch heute noch Programme aus den 80ern ohne Code-Änderung,
> welche auf 64-Bit-Systemen ganz normal mit mehreren GB großen Dateien
> umgehen können.

Für "mehrere" = "zwei oder vier".

von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
>> uint8_t, uint16, uint32_t usw. sind immer so breit wie der Bezeichner
>> aussagt.
>
> Und das kommt daher, daß sie nur ein Alias des jeweils passenden
> Grundtyps sind, hingeschrieben von einem Zulieferer.

Genauso, wie derselbe oder auch andere Zulieferer den Compiler, Linker, 
und alle weiteren toolchain-Tools an die Architektur anpassen, dazu die 
Stdlib, die Linkerscripts, und alles andere, was eine konkrete 
Implementierung des abstrakten Konzepts „Programmiersprache C“ 
erfordert.

Das gilt nicht nur für C, sondern für alle Programmiersprachen.

Oliver

von Mombert H. (mh_mh)


Lesenswert?

MaWin schrieb:
> Rust löst das wesentlich besser.

Wie löst rust das denn besser?

von (prx) A. K. (prx)


Lesenswert?

Rust verwendet andere Namen. i32 statt int32_t, und isize statt int.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Mombert H. schrieb:
> Wie löst rust das denn besser?

Rust hat integer-Typen mit fester Breite (u32, i32, u16, i16, usw), plus 
einen Typ für native Breite (usize / isize).

von Mombert H. (mh_mh)


Lesenswert?

MaWin schrieb:
> Mombert H. schrieb:
>> Wie löst rust das denn besser?
>
> Rust hat integer-Typen mit fester Breite (u32, i32, u16, i16, usw), plus
> einen Typ für native Breite (usize / isize).

Also weniger ausdrucksstark als C oder C++.

von MaWin (Gast)


Lesenswert?

Mombert H. schrieb:
> Also weniger ausdrucksstark als C oder C++.

Warum das?

von XY M. (xym)


Lesenswert?

(prx) A. K. schrieb:
> Hier beziehst du dich auf Assembler vs Compiler Diskussionen, die vor
> einigen Jahren recht heftig abliefen und einen Teilnehmer so in Rage
> brachten, dass er aus dem Forum flog.

Da mach Dir mal keine Sorgen.
Derjenige ist im Forum so aktiv wie eh und je und verfolgt Diskussionen 
wie diese hier höchst belustigt. Weil es die Vorteile simplen Assemblers 
gegenüber den immer komplexeren Hochsprachen immer wieder aufs 
Herrlichste bestätigt ;-)

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Wissender schrieb:
>> int, long usw. sind Architekturabhängig.
>
> Ja eben. Genau DAS war es, was ich genannt habe. Und alle Alias, die
> in irgendeiner Headerdatei erzeugt werden, wären per se eben genauso
> abhängig.

Ja, klar. Bei Standardheadern ist es doch ganz normal, dass diese genau 
für den Compiler, mit dem sie ausgeliefert werden, gemacht und daher 
auch davon abhängig sind. Da ist stdint.h natürlich keine Ausnahme.

> Eben deshalb wird es den Toolherstellern oder sonstigen Zulieferern
> anheimgestellt, besagte Headerdateien so zu schreiben, daß das Gewünschte
> dabei herauskommt.

Selbstverständlich ist es die Aufgabe des Herstellers der 
Compiler-Toolchain, alle Komponenten so zusammenzustellen, dass sie auch 
zusammenpassen. Auch hier gibt's keinen Grund, warum stdint.h eine 
Sonderrolle haben sollte.

>> uint8_t, uint16, uint32_t usw. sind immer so breit wie der Bezeichner
>> aussagt.
>
> Und das kommt daher, daß sie nur ein Alias des jeweils passenden
> Grundtyps sind, hingeschrieben von einem Zulieferer.

Wenn die Typen fest im Compiler eingebaut wären, dann wären sie halt im 
Quellcode des Compiler "hingeschrieben von einem Zulieferer". Macht also 
auch in der Hinsicht keinen Unterschied.

von Thomas Z. (usbman)


Lesenswert?

W.S. schrieb:
> Wissender schrieb:
>> int, long usw. sind Architekturabhängig.
>
> Ja eben. Genau DAS war es, was ich genannt habe. Und alle Alias, die
> in irgendeiner Headerdatei erzeugt werden, wären per se eben genauso
> abhängig. Eben deshalb wird es den Toolherstellern oder sonstigen
> Zulieferern anheimgestellt, besagte Headerdateien so zu schreiben, daß
> das Gewünschte dabei herauskommt.

nun auch wenn du gerne Pascal lobst:
Dort ist es ganz genauso TP war ein 16Bit Compiler integer somit 16 bit 
breit.
Heute ist das eben 32bit.

von (prx) A. K. (prx)


Lesenswert?

Vielleicht ist ja PL/I genehm:

FIXED BINARY (VK,NK)  - i.A. zu BIN(...) abgekürzt
VK = Anzahl Vorkommastellen
NK = Anzahl Nachkommastellen
Vorzeichen geht extra
int16_t entspricht also BIN(15,0)
int entspricht BIN ohne (...)

Sowas ging dann natürlich auch zwanglos auf Maschinen mit 24, 36 oder 48 
Bit, oder was immer die Kisten früher hatten. Man schreibt hin, was man 
braucht, nicht was die Kiste hat.

Ein brauchbarer Subset von PL/I passte tatsächlich in ein normales 64 KB 
CP/M System auf 8080. War vor Turbo Pascal gar nicht mal so übel.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.