Hallo,
wie sind eigentlich die standard datentypen implementiert?
Wenn ich in die stdint.h gucke sehe ich nur ein mapping zu den
Datentypen welche ich verwende
1
typedef signed char int8_t;
2
typedef unsigned char uint8_t;
3
typedef short int16_t;
4
typedef unsigned short uint16_t;
5
typedef int int32_t;
6
typedef unsigned uint32_t;
7
typedef long long int64_t;
8
typedef unsigned long long uint64_t;
aber wie ist z.B. unsigned long long implementiert?
Diesen kann ich ja auch auf einem AVR (8Bit) benzutzen.
Wäre es möglich so auch noch größere Datentypen zu implementieren (z.B.
uint128_t) ?
Chandler B. schrieb:> Wäre es möglich so auch noch größere Datentypen zu implementieren (z.B.> uint128_t) ?
Für die nativen Typen gibt es fertige Funktionen und Operatoren.
Für eigene Typen muss man das alles selber bauen.
C++ bietet die Chance, in C sind da mehr Kompromisse nötig.
Chandler B. schrieb:> aber wie ist z.B. unsigned long long implementiert?
In der Sprachdefinition selber, also im Compiler.
Chandler B. schrieb:> aber wie ist z.B. unsigned long long implementiert?> Diesen kann ich ja auch auf einem AVR (8Bit) benzutzen.
Der Compiler muss fuer die Datentypen speziellen Code generieren, das
beginnt damit, dass beim Laden aus dem RAM die einzelnen Byte in
verschiedene Register geladen werden. Dann muss je nach Operation
bestimmter Code erzeugt werden. Bspw. fuer Additionen gibt es das
Carry-Flag, zuerst werden die beiden niederwertigen Byte addiert, kommt
es zum Ueberlauf bei der Addition dann setzt die CPU das Carryflag,
welches bei der Addition der naechsten beiden Byte dann beruecksichtigt
wird (Uebertrag). Oder beim Vergleich zweier Zahlen muessen alle Bytes
verglichen werden, ja nach Art des Vergleichs (kleiner/groesser/gleich)
eben unterschiedlich. Der Compiler nimmt einem da viel Arbeit ab.
Verursacht aber bei grossen Datentypen auch einiges an Code.
Chandler B. schrieb:> aber wie ist z.B. unsigned long long implementiert?> Diesen kann ich ja auch auf einem AVR (8Bit) benzutzen.
Na ja, "implementiert" sind die so, wie es in der Doku zum Compiler
steht. In den allermeisten Fällen als benötigte Anzahl Bytes
hintereinander, und dann halt big oder little endian.
Chandler B. schrieb:> Wäre es möglich so auch noch größere Datentypen zu implementieren (z.B.> uint128_t) ?
Es gibt Compiler-Versionen, die 128-Byte Datentypen unterstützen.
Allerdings nicht für AVR.
Oliver
Chandler B. schrieb:> typedef unsigned char ...
In der Programmiersprache C gibt es Variablen-Typen wie char, int und
float. Solche Dinge wie signed oder unsigned sowie short oder long sind
Attribute, die man zusätzlich angeben kann. Und genau DAS ist es, was
der Compiler eigentlich versteht. Alle solchen "Datentypen" wie uint16_t
oder so sind lediglich Alias-Namen für die eigentlichen Typen. Man
könnte sowas auch 'ottokar' oder 'karlheinz' nennen:
1
typedefunsignedcharottokar;
aber das macht keiner, weil es nicht technisch genug klingt.
Das ist eigentlich alles.
W.S.
Oliver S. schrieb:> Es gibt Compiler-Versionen, die 128-Byte Datentypen unterstützen.> Allerdings nicht für AVR.
Wie kommst du auf AVR? Ich kenne keine wo int 32Bit ist und 64Bit werden
dort meines wissens nach auch nicht unterstützt.
Chandler B. schrieb:> wie sind eigentlich die standard datentypen implementiert?>> Wenn ich in die stdint.h gucke sehe ich nur ein mapping zu den> Datentypen welche ich verwende
Implementiert, wie schon erwähnt im Programmcode des Compilers.
Das Interessante an den Typen die in stdint.h definiert sind, ist das
sie eben von verwendetem Compiler und CPU-Architektur weitestgehend
unabhängig sind. Vorausgesetzt das ganze unterstützt was Vergleichbares.
Wenn nein, merkt man an der Fehlermeldung aber ganz schnell das es
diesen Type nicht gibt. 128Bit wirst du nur auf 64Bit Architekturen
finden.
Bestes Beispiel ist "int", der ist je nach System 16Bit, 32Bit oder
64Bit. Ein int32_t ist auch auf einer 8bit-Gurke 32Bit breit und eben
nicht 16Bit wie int.
-
https://stackoverflow.com/questions/16088282/is-there-a-128-bit-integer-in-gcc
Irgend W. schrieb:> Das Interessante an den Typen die in stdint.h definiert sind, ist das> sie eben von verwendetem Compiler und CPU-Architektur weitestgehend> unabhängig sind.
Nein, genau SO HERUM ist es eben nicht. Solche Dinge wie all das, was in
stdint.h definiert ist, muß mittels der zu dem jeweiligen Compiler
passenden stdint.h in die eigentlichen Grundtypen zurückübersetzt
werden, damit aus Sicht des Anwenders dieser Toolchain eine
plattformunabhängiger Datentyp erzielt werden kann. Genau deshalb ist
das eben compiler- bzw. plattformspezifisch und keinesfalls unabhängig.
Also nochmal: die Datentypen bei C sind schwammig definiert (z.B. keine
fest definerten Längen) und die Präzisierung mit Attributen (long oder
short, signed oder unsigned etc.) ist den typischen C-Programmierern zu
lästig hinzuschreiben, weswegen in der Vergangenheit viele sich eigene
Kürzel geschaffen haben: U8 oder U16 (jedoch m.W. nirgends 'ottokar').
Das hatte nun ein Gremium aufgegriffen und gesagt: "wir wollen alle eben
diese Datentypen umbenennen und dabei uniformierte Bezeichner wählen, so
daß bei der Verwendung durch den Programmierer auf allen Maschinen ein
zum vom Programmierer gewünschten Zweck der jeweils passende eigentliche
Datentyp je nach Compiler verwendet werden soll. Am Compiler oder der
Sprache C selbst findet keine Änderung statt."
Anstatt also die vom Compiler verstandenen Datentypen zu reformieren,
wurde eine stdint.h vorgeschlagen, die als Übersetzungsmedium zum
Compiler hin fungieren soll. Diese Datei ist compilerspezifisch. Rein
theoretisch könnte man daher seine Datentypen auch ottokar oder
karlheinz nennen. Das ist alles nur eine Wortersetzungs-Frage letztlich.
W.S.
W.S. schrieb:> Diese Datei ist compilerspezifisch
Genau genommen Compiler & Architektur spezifisch. Teilweise sogar noch
das ABI.
Hier mal vom SCC für Z80
W.S. schrieb:> Irgend W. schrieb:>> Das Interessante an den Typen die in stdint.h definiert sind, ist das>> sie eben von verwendetem Compiler und CPU-Architektur weitestgehend>> unabhängig sind.>> Nein, genau SO HERUM ist es eben nicht. Solche Dinge wie all das, was in> stdint.h definiert ist, muß mittels der zu dem jeweiligen Compiler> passenden stdint.h in die eigentlichen Grundtypen zurückübersetzt> werden, damit aus Sicht des Anwenders dieser Toolchain eine> plattformunabhängiger Datentyp erzielt werden kann. Genau deshalb ist> das eben compiler- bzw. plattformspezifisch und keinesfalls unabhängig.
Ihr redet da von unterschiedlichen Aspekten. Auf welche eingebauten
Datentypen die typedefs wie uint32_t gemappt sind, ist
plattformabhängig. Wie groß sie sind, ist es aber natürlich nicht. Das
ist ja gerade der Sinn dahinter.
W.S. schrieb:> Also nochmal: die Datentypen bei C sind schwammig definiert (z.B. keine> fest definerten Längen)
Der Standard definiert die „schwammig“, aber eine Implementierung
definiert die dann natürlich vollständig.
> und die Präzisierung mit Attributen (long oder> short, signed oder unsigned etc.) ist den typischen C-Programmierern zu> lästig hinzuschreiben,
Das ist natürlich Unsinn.
> Das hatte nun ein Gremium aufgegriffen und gesagt: "wir wollen alle eben> diese Datentypen umbenennen und dabei uniformierte Bezeichner wählen, so> daß bei der Verwendung durch den Programmierer auf allen Maschinen ein> zum vom Programmierer gewünschten Zweck der jeweils passende eigentliche> Datentyp je nach Compiler verwendet werden soll.
Den Satz verstehst du doch selber nicht mehr…
Die in stdint.h definierten Typen sind Datentypen mit eindeutiger Größe,
die man direkt erkennen kann.
Oliver
Oliver S. schrieb:> Den Satz verstehst du doch selber nicht mehr…
Naja, ich schon, du anscheinend nicht.
Deshalb sag ich es nochmal ein bissel unfreundlicher:
Anstatt endlich einmal die Größen von int und long int in C hinzukriegen
und damit den jeweiligen Compiler zu modernisieren, hat man sich zu
nichts besserem als einer Headerdatei entschließen können. Die soll nun
für mehr Compilerunabhängigkeit sorgen, indem sie die von Programmierer
zu gebrauchenden Bezeichnungen (wie uint8_t) auf die vom Compiler
verstandenen Bezeichnungen (wie unsigned char) umsetzt.
Ganz kurz: Keine Modernisierung, sondern wieder mal nur ein popliger
workaround.
Nur schade, daß die nicht Bezeichner wie 'ottokar' genommen haben. X-)
Das wäre wenigstens lustig.
W.S.
> Ganz kurz: Keine Modernisierung
Genau das ist das zentrale Feature an C.
Du kannst immer noch 50 Jahre alte Libraries in dein neues Programm
einbinden. Jede Verbesserung muss zu den prähistorischen K&R
Konstruktionen kompatibel sein.
Die meisten Leute wollen es genau so haben. Sonst wäre C schon längst in
der Versenkung verschwunden. Eine der modernen Śprachen hätte sich
durchgesetzt.
Übrigens: Mit C++ operator overloading kannst du dir uint128_t selbst
basteln. Aber die Frage, ob das eine gute Idee ist, löst garantiert
einen Religionskrieg aus.
Noch ein Kommentar schrieb:> Übrigens: Mit C++ operator overloading kannst du dir uint128_t selbst> basteln. Aber die Frage, ob das eine gute Idee ist, löst garantiert> einen Religionskrieg aus.
Wenn man es braucht, muß man das machen. Wobei, müssen muß man nicht,
man kann auch einfach eine der verfügbaren „bigint“ libs benutzen, und
damit noch viel größere Integertypen nutzen. Auch unter C.
Oliver