Forum: Mikrocontroller und Digitale Elektronik Suffix für uint8_t


von Sebastian (Gast)


Lesenswert?

Hallo, ich habe folgendes Problem:
Wenn ich zu einem uint8_t einen festen Wert addiere übersetzt mein 
Compiler(arm-none-eabi-gcc) das zu einer Integerrechnung. Für mich ist 
es aber wichtig, dass es ein uint8_t bleibt. Sonst drohen Zugriffe auf 
undefinierte Speicherabschnitte.
Beispiel:
int32_t  Array[256];
uint8_t  ZaehlVariable;
int32_t  Variable;
Variable = Array[ZaehlVariable+20];

In diesem Beispiel wird die 20 als Integer erkannt und die Rechnung als 
Integerrechnung durchgeführt und damit wird auch das Ergebnis ein 
Integer.
Für float-Wert kenne ich die Möglichkeit 3.14f zu schreiben (für 
unsigned int 20u, für unsigned long 20ul) damit der Compiler das 
richtige Format an nimmt und zur Richtigen Instruktion übersetzt. Gibt 
es das auch für char (z.B. 20uc)?
Einen Cast   Variable = Array[(uint8_t)(ZaehlVariable+20)];   möchte ich 
nicht machen, denn das Übersetzt der Compiler zu einer Integerrechnung 
und einem Cast, was ein zusätzlicher Rechenschritt ist.
Hierfür gibt es doch sicher eine einfache, elegante Lösung.
Vielen Dank schon mal im voraus.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Variable = Array[(uint8_t) (ZaehlVariable+20)];

: Bearbeitet durch Moderator
von B. S. (bestucki)


Lesenswert?

Sebastian schrieb:
> Einen Cast   Variable = Array[(uint8_t)(ZaehlVariable+20)];   möchte ich
> nicht machen, denn das Übersetzt der Compiler zu einer Integerrechnung
> und einem Cast, was ein zusätzlicher Rechenschritt ist.
1
Variable = Array[(ZaehlVariable+20) & 0xFF];

Ob das nun besser als ein Cast ist, musst du selbst entscheiden.

von Oliver S. (oliverso)


Lesenswert?

Sebastian schrieb:
> Einen Cast   Variable = Array[(uint8_t)(ZaehlVariable+20)];   möchte ich
> nicht machen, denn das Übersetzt der Compiler zu einer Integerrechnung
> und einem Cast, was ein zusätzlicher Rechenschritt ist.

Ein cast ist in dem Fall kein zusätzlicher Rechenschritt. Allerdings ist 
nunmal in C ein Arrayindex per Definition ein Integer, daran kannst du 
auch mit casten nichts ändern.

Es geht aber so:
1
uint8_t tmpIndex = ZaehlVariable + 20;
2
Variable = Array[tmpIndex];

Oliver

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Sebastian schrieb:
> Einen Cast   Variable = Array[(uint8_t)(ZaehlVariable+20)];   möchte ich
> nicht machen, denn das Übersetzt der Compiler zu einer Integerrechnung
> und einem Cast, was ein zusätzlicher Rechenschritt ist.
Hast du das im Assemblerlisting nachgesehen? Oder rätst du nur?

Es ist sowieso klar, dass ein 32 Bit Prozessor jede Rechnung mit 32 
Bit ausführt. Du kannst nur bestimmen, welchen Teil des Ergebnisses du 
hinterher verwenden willst...

von Peter II (Gast)


Lesenswert?

Sebastian schrieb:
> Einen Cast   Variable = Array[(uint8_t)(ZaehlVariable+20)];   möchte ich
> nicht machen, denn das Übersetzt der Compiler zu einer Integerrechnung
> und einem Cast, was ein zusätzlicher Rechenschritt ist

das optimiert er doch weg.
1
Variable = Array[(ZaehlVariable+20)&0xFF];
sollte auch gehen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Es ist sowieso klar, dass ein 32 Bit Prozessor jede Rechnung mit 32
> Bit ausführt.

Eben. Bei Rechnungen in kleineren Einheiten kostet das beim STM32 eher 
mehr Zeit. Entsprechende Tests habe ich schon gemacht. Seitdem habe ich 
bei Source-Portierungen von AVR nach STM32 sehr viel Gefallen an den 
uint_fastXt Typen gefunden. So bleibt der Source portabel und der STM32 
kann trotzdem mit Vollgas arbeiten - solange man Überläufe nicht 
implizit ausnutzt, wie der TO das will. Ich halte das für unsauber. 
Besser wäre dann eine explizite Maskierung mit 0xFF.

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Besser wäre dann eine explizite Maskierung mit 0xFF.
Allemal. Und optimiert wird diese Berechnung dann sowieso...

von Sebastian (Gast)


Lesenswert?

Vielen Dank für die schnellen Antworten.
die Möglichkeit das Ergebnis mit einer &-Operation zu begrenzen
Variable = Array[(ZaehlVariable+20)&0xFF];
ist im Endeffekt das gleiche wie der Cast
Variable = Array[(uint8_t) (ZaehlVariable+20)];.
Allerdings ist in beiden Fällen ein weiterer Rechenschritt notwendig.
Ich 320 dieser Rechnungen in einem engen Rahmen zu machen und der 
zusätzliche Rechenschritt erhöht meine Durchlaufzeit um mehr als 10%.
Ich hatte gehofft ich kann das umgehen in dem ich dem Compiler die Art 
seiner Rechnung von vornerein vorgeben kann.

von Peter II (Gast)


Lesenswert?

Sebastian schrieb:
> Allerdings ist in beiden Fällen ein weiterer Rechenschritt notwendig.

nein nicht wirklich. Schau dir den ASM-Code an, dann sieht du was 
wirklich passiert.

Wenn man dir Sagt das du die letzte stelle von 1234 nennen sollte, 
rechnest du auch nicht.

von Carl D. (jcw2)


Lesenswert?

Bei Array[256] ist aber max(uint8_t)+20 auch außerhalb. Das funktioniert 
also auch nicht "implizit", sonder ist schlicht buggy Code. Und zwar auf 
jeder Plattform.

von Sebastian (Gast)


Lesenswert?

Lothar M. schrieb:
> Hast du das im Assemblerlisting nachgesehen? Oder rätst du nur?

Ich habe die Durchlaufzeiten gemessen und es ist eindeutig, dass die 
Zeiten mit dem Cast länger werden.

von DirkB (Gast)


Lesenswert?

Sebastian schrieb:
> Ich habe die Durchlaufzeiten gemessen und es ist eindeutig, dass die
> Zeiten mit dem Cast länger werden.

Gegenüber welchem Code?
Der ohne Cast ist falsch, den kanst du also nicht als Referenz nehmen.
Du kannst nur den Code mit Cast mit dem mit & vergleichen.

Oder, wenn es so zeitkritisch ist, Assembler nehmen.

Hast du die Optimierung an? Welche?

von Carl D. (jcw2)


Lesenswert?

Was eigentlich gewünscht ist:
1
Array[(ZaehlVariable+20)%256];
Das das per "&0xFF" geht, bekommt der Compiler selber hin. Es bleibt 
aber richtig, wenn die Array-Größe mal nicht 256 sein sollte.

von B. S. (bestucki)


Lesenswert?

Carl D. schrieb:
> Array[(ZaehlVariable+20)%256];Das das per "&0xFF" geht, bekommt der
> Compiler selber hin. Es bleibt
> aber richtig, wenn die Array-Größe mal nicht 256 sein sollte.

Wenn schon, denn schon:
1
Array[(ZaehlVariable + 20) % (sizeof(Array) / sizeof(*Array))];

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sebastian schrieb:
> uint8_t  ZaehlVariable;

Sebastian schrieb:
> Ich habe die Durchlaufzeiten gemessen und es ist eindeutig, dass die
> Zeiten mit dem Cast länger werden.

Dann versuche, uint8_t generell und insbesondere bei Zählvariablen zu 
vermeiden! Nimm uint_fast8t. Damit laufen zum Beispiel Schleifen über 
die Zählvariablen um einiges schneller.

Allerdings musst Du dann alle bisher implizit einkalkulierten Überläufe 
selber mit & 0xFF in Ordnung bringen, da auf dem STM32 ein uint_fast8t 
denselben Wertebereich wie ein uint32_t hat.

: Bearbeitet durch Moderator
von Sebastian (Gast)


Lesenswert?

@Dirk B:
Du hast recht ich habe es mit dem falschen Code, ohne Cast verglichen.
Hier rechnet er über das Array hinaus, aber schnell.
Das mit dem uint_fast8_t wird ich mir ansehen, das habe ich noch nicht 
benutzt. Wenn das nicht klappt werde ich wohl den Cast oder das &0xFF 
nehmen und wenn es zum Schluss zeitlich nicht reicht werde ich es mal 
mit Assembler versuchen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sebastian schrieb:
> Das mit dem uint_fast8_t wird ich mir ansehen, das habe ich noch nicht
> benutzt.

uint_fast8_t benutzt immer den Typ, mit dem der konkrete µC am 
schnellsten rechnen kann. Auf dem STM32 ist es identisch mit uint32_t, 
auf einem ATmega oder ATtiny ist es identisch mit uint8_t.

Das heisst konkret für den STM32: Er rechnet in 32-Bit sauschnell. 
Allerdings ist ein Wert größer als 255 durchaus möglich. Dem musst du 
selbst vorbeugen.

Du fragst Dich sicher: "Warum soll ich denn dann nicht direkt uint_32t 
nehmen".

Für mich gibt es da 2 Gründe:

  1. Mnemotechnisch: Du sagst dem Leser des Codes: Das ist eine
     Variable, deren Wertebereich bis 255 geht. Allerdings muss ich
     mich selber drum kümmern, dass dieser Wertebereich auch
     eingehalten wird.

  2. Portabilität: Von 8-Bit bis 32-Bit µC sauschnell

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


Lesenswert?

Peter II schrieb:
>> Allerdings ist in beiden Fällen ein weiterer Rechenschritt notwendig.
>
> nein nicht wirklich. Schau dir den ASM-Code an, dann sieht du was
> wirklich passiert.

Hier ist ein ARM am Werk, kein AVR oder x86. Und ein ARM kann nicht mit 
8 Bits rechnen. Der rechnet immer mit 32 Bits und muss ggf. 
anschliessend maskieren. Was immer der TE also macht, die effiziente 
reine 8-Bit Rechnung, die er sich vorstellt, wird er nicht kriegen. 
Nicht in C, aufgrund der Sprachdefinition, aber auch nicht in Assembler.

Es ist daher schon so wie Frank schreibt. Wenn man versucht, jedes 
einzelne Zwischenergebnis auf 8 Bits runterzubrechen, egal ob per 
Variablendeklaration oder Cast, schmeisst man dem Compiler bloss Knüppel 
zwischen die Beine. Denn das kostet.

: Bearbeitet durch User
von Sebastian (Gast)


Lesenswert?

@A.K. sehr präzise Antwort
Ich werde es jetzt mit der Maskierung machen.
Vielen Dank an alle.

von B. S. (bestucki)


Lesenswert?

Frank M. schrieb:
> 2. Portabilität: Von 8-Bit bis 32-Bit µC sauschnell

Richtig. Für Grössenangaben, also z.B. für einen Index eines Arrays, 
würde ich jedoch size_t empfehlen. Da der Operator sizeof auf jedes 
Objekt angewandt werden kann und sein Ergebnis als size_t liefert, kann 
kein Objekt im Speicher, auch kein Array, mehr als SIZE_MAX Bytes 
belegen.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Portabel bedeutet auch, daß man hinschreibt, was man meint. Ein Array 
als "Ringpuffer" zu betreiben, indem man auf das Überlaufverhalten einer 
Variable hofft, taugt nichts. Wenn man Dinge wie "2^n" als Arraygröße 
ausnutzen will, dann schreibt man das in den Kommentar, den Code aber 
so, daß er mit jeder Größe funktioniert. Und wenn ein Compiler damit 
nicht umgehen kann, sprich 2^n nicht erkennt, dann sollte man sich einen 
besseren suchen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

be s. schrieb:
> Für Grössenangaben, also z.B. für einen Index eines Arrays,
> würde ich jedoch size_t empfehlen.

Das halte ich für nicht optimal. size_t ist auf einem AVR 16 Bit groß. 
Das heisst, ich sollte nach Deiner Vorstellung eine Indexvariable vom 
Typ uint_16t nehmen. Das wäre auf einem AVR aber längst nicht die 
optimale Wahl, wenn mein Array eine Größe von weniger als 256 Elementen 
hat.

: Bearbeitet durch Moderator
von B. S. (bestucki)


Lesenswert?

Frank M. schrieb:
> Das halte ich für nicht optimal. size_t ist auf einem AVR 16 Bit groß.
> Das heisst, ich sollte nach Deiner Vorstellung eine Indexvariable vom
> Typ uint_16t nehmen. Das wäre auf einem AVR aber längst nicht die
> optimale Wahl, wenn mein Array eine Größe von weniger als 256 Elementen
> hat.

Da hast du natürlich recht. Andererseits programmiere ich lieber 
portabel, als dass ich voreilige Optimierungen vornehme, die 
wahrscheinlich gar nicht nötig sind. Bisher hatte ich noch nie das 
Problem, dass aufgrund eines 16Bit statt 8Bit Indizes das Programm zu 
langsam war oder nicht mehr in den Programmspeicher passte. Sollte es 
aber jemals nachweislich daran scheitern, würde ich diese 
Handoptimierung nicht scheuen (zumal sie wahrscheinlich nur an ein, zwei 
Stellen nötig wäre).

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


Lesenswert?

be s. schrieb:
> Bisher hatte ich noch nie das
> Problem, dass aufgrund eines 16Bit statt 8Bit Indizes das Programm zu
> langsam war oder nicht mehr in den Programmspeicher passte.

Möglicherweise bist du von AVRs verwöhnt. Schon mal mit grösseren 
Datentypen auf einer 8-Bit Akkumulator-Architektur in C gearbeitet? 
Selbst wenn das in Platz und Zeit reicht kriegt man mitunter 
Hirnkrämpfe, wenn man den erzeugten Code anschaut. Besonders bei solchen 
Zierden wie den 12/14-Bit PICs.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

be s. schrieb:
> Andererseits programmiere ich lieber portabel

Das mache ich auch, versuche aber trotzdem optimalen Code zu erreichen. 
Und das geht! Eine Verwendung einer 16-Bit-Variablen als Index ist für 
mich in 99% aller Fälle ein No-Go. Die käme für mich tatsächlich nur in 
Frage, wenn das Array mehr als 255 Elemente hat. Aber wann ist das schon 
so?

Ich kann beim besten Willen keine Portabilität beim Verwenden eines 
size_t für Indexvariablen von Arrays erkennen. Magst Du mir diese 
erläutern?

(Das Argument, dass size_t wegen SIZE_MAX Bytes immer jedes theoretisch 
noch so große Array abdeckt, ist für mich keines. Denn es gibt in den 
meisten Fällen gar keine "theoretisch noch so große Arrays". In den 
allermeisten Fällen sind sie wesentlich kleiner.)

Vielleicht verwechselst Du Portabilität mit Codesicherheit?

: Bearbeitet durch Moderator
von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Das halte ich für nicht optimal. size_t ist auf einem AVR 16 Bit groß.
> Das heisst, ich sollte nach Deiner Vorstellung eine Indexvariable vom
> Typ uint_16t nehmen. Das wäre auf einem AVR aber längst nicht die
> optimale Wahl, wenn mein Array eine Größe von weniger als 256 Elementen
> hat.

Bin mir nicht sicher, ob auch deine 8bit nicht als 16bit übergeben 
werden. Intern ist es eine Addition mit Adressen. Die wird immer mit int 
gerechnet.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Bin mir nicht sicher, ob auch deine 8bit nicht als 16bit übergeben
> werden. Intern ist es eine Addition mit Adressen. Die wird immer mit int
> gerechnet.

Du hast das im falschen Kontext gelesen. Wir sind da schon weiter, bitte 
genauer lesen.

Meine Formulierung war nicht auf das Problem des TOs bezogen, sondern 
auf Stuckis Aussage, man solle generell size_t als Typ für 
Indexvariablen nehmen.

Das halte ich - speziell auf AVRs - für suboptimal.

von (prx) A. K. (prx)


Lesenswert?

Frank M. schrieb:
> Denn es gibt in den
> meisten Fällen gar keine "theoretisch noch so große Arrays".

"640 kB ought to be enough for anybody."

von Oliver S. (oliverso)


Lesenswert?

Frank M. schrieb:
> Ich kann beim besten Willen keine Portabilität beim Verwenden eines
> size_t für Indexvariablen von Arrays erkennen.

Der "Vorteil" ist eher Gewöhnung aus der PC-Programmierung. Die 
STL-Container geben halt alle ihre Größenangaben in size_t zurück, und 
spätestens bei der Compilierung für 64-Bit haut einem der Compiler 
begründete Warnungen um die Ohren, wenn man die mit Integern vermischt. 
Dann landet man zwangsweis dabei, für solche Größen den dafür gedachten 
size_t und seine Verwandten zu verwenden.

Oliver

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> Bin mir nicht sicher, ob auch deine 8bit nicht als 16bit übergeben
> werden. Intern ist es eine Addition mit Adressen. Die wird immer mit int
> gerechnet.

Nicht die Adressrechnung selbst ist davon wesentlich betroffen, denn die 
läuft immer in size_t. Der Kram drumherum jedoch kann es sein, also die 
Handhabung vom Index ausserhalb der eigentlichen Adressierung. Je nach 
Umgebung ist mal dies mal jenes besser. Mit uint_fast8_t liegt man stets 
auf der effizienten Seite, mit size_t nicht überall.

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

A. K. schrieb:
> Möglicherweise bist du von AVRs verwöhnt. Schon mal mit grösseren
> Datentypen auf einer 8-Bit Akkumulator-Architektur in C gearbeitet?
> Selbst wenn das in Platz und Zeit reicht kriegt man mitunter
> Hirnkrämpfe, wenn man den erzeugten Code anschaut. Besonders bei solchen
> Zierden wie den 12/14-Bit PICs.

Ich hab mit den alten 16er PICs angefangen, nicht ohne Grund habe ich 
die alten PICs (10/12/16/18) hinter mir gelassen. Da gibt es noch ganz 
andere Fallstricke wie z.B. ein 8-stufiger Hardwarestack (alte 16er, 
vergiss den Interrupt nicht...). Die neueren 18er sind eher wieder gut 
zu gebrauchen, die 24er und 32er habe ich nie verwendet, diese fallen 
aber so oder so in eine andere Kategorie.

Frank M. schrieb:
> Eine Verwendung einer 16-Bit-Variablen als Index ist für
> mich in 99% aller Fälle ein No-Go. Die käme für mich tatsächlich nur in
> Frage, wenn das Array mehr als 255 Elemente hat. Aber wann ist das schon
> so?

Wenn ich eine Bibliothek schreibe, die mit übergebenen Arrays hantiert, 
kann ich zum Voraus unmöglich wissen, wie gross das Array ist. Die 
gesamte Bibliothek umschreiben, nur weil ich diese später auf einem 
grösseren uC oder auf dem PC mit Arraygrössen > 256 nutzen will? Nein 
Danke.
Für ein lokales Array bin ich mit dir einverstanden, da kann man sowas 
machen, ich tus nicht.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Der "Vorteil" ist eher Gewöhnung aus der PC-Programmierung.

Ja, den "Vorteil" sehe ich natürlich ein. Für einen PC oder Server 
programmiere ich auch ganz anders. Da bringt es überhaupt nichts, mit 
uint_fast8 zu kleckern. Ich käme da auch nie in den Sinn, so etwas zu 
nutzen. Allerdings habe ich auch schon Programme geschrieben, die auf 
einem AVR, Linux und auch Windows laufen. Dann wird gekleckert, sonst 
geklotzt. Wobei man "Klotzen" jetzt nicht mit Speicherverschwendung 
verwechseln sollte.

Es kommt immer drauf an, ob man auf bestimmte Zielplattformen Rücksicht 
nehmen muss oder nicht. Handelt es sich beispielsweise um ein 
STM32-Programm, welches niemals auf einen 8-Bit-µC portiert werden 
wird: Scheiss auf uint_fast8t. Nimm direkt int oder unsigned int oder 
auch speziell bei Indexvariablen size_t.

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


Lesenswert?

A. K. schrieb:
> Mit uint_fast8_t liegt man stets
> auf der effizienten Seite, mit size_t nicht überall.

Korrektur: Stimmt leider auch nicht. Da mindestens in Linux auf einer 
32/64-Bit Kiste mit 8-Bit Operationen wie x86(-64) der Typ uint_fast8_t 
mit 8-Bits definiert ist, ist man da mit size_t besser dran als damit.

Das Ei des Kolumbus gibts dafür also nicht.

von B. S. (bestucki)


Lesenswert?

Frank M. schrieb:
> Handelt es sich beispielsweise um ein
> STM32-Programm, welches niemals auf einen 8-Bit-µC portiert werden
> wird: Scheiss auf uint_fast8t. Nimm direkt uint32_t.

Das sehe ich anders, ist sicher aber auch Geschmackssache. Warum sollte 
ich für eine Membervariable einer Klasse etwas anderes als uint_least8_t 
verwenden, wenn ich nur die Werte 0, 1, 2 und 3 speichern muss?

Ja ich weiss, es gibt Plattformen, bei denen solche Speicherzugriffe 
extremst ineffizient sind. Andererseits könnte die Klasse auch X-Mal im 
Speicher liegen, dann machts schon einen Unterschied, ob 1M * 1Byte oder 
1M * 4Byte (je nach Plattform natürlich). Aber es ist so wie mit allem, 
allen kann mans nicht rechtmachen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

be s. schrieb:
> Wenn ich eine Bibliothek schreibe, die mit übergebenen Arrays hantiert,
> kann ich zum Voraus unmöglich wissen, wie gross das Array ist.

Das ist korrekt. Außer es gibt schon technische Beschränkungen, die eine 
obere Grenze vorgeben.

Aber wie A.K. schon zitierte: "640 kB ought to be enough for anybody."

Da hat er Recht - und damit Du auch.

von (prx) A. K. (prx)


Lesenswert?

be s. schrieb:
> Das sehe ich anders, ist sicher aber auch Geschmackssache. Warum sollte
> ich für eine Membervariable einer Klasse etwas anderes als uint_least8_t
> verwenden, wenn ich nur die Werte 0, 1, 2 und 3 speichern muss?

Aufgrund des möglicherweise zusätzlichen Aufwands für den Umgang mit 
8-Bit Daten in lokalen Variablen? Es hängt also von der Verwendung ab. 
Im Speicher minimieren, im Register an den Maschinenworten orientieren.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Da mindestens in Linux
> auf einer 32/64-Bit Kiste mit 8-Bit Operationen wie x86(-64) der Typ
> uint_fast8_t mit 8-Bits definiert ist, ist man da mit size_t besser
> dran als damit.

Habe es gerade mal geprüft. Tatsächlich ist dem so:

        sizeof (uint_fast8_t)

ist unter Linux (32/64) tatsächlich 1.

Verstehen kann ich das nicht. Siehst Du dafür einen Grund?

> Das Ei des Kolumbus gibts dafür also nicht.

Korrekt.

: Bearbeitet durch Moderator
von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Siehst Du dafür einen Grund?

warum sollte auf einem x68 64bit schneller als 8bit sein?

mehrere 8bit Operationen können gleichzeitig gemacht werden.

von (prx) A. K. (prx)


Lesenswert?

Frank M. schrieb:
> Verstehen kann ich das nicht. Siehst Du dafür einen Grund?

Bei uint_fast8_t stand offenbar nicht die Verwendung als Index im 
Vordergrund, sondern der normale Umgang bei Rechnungen, Vergleichen etc. 
Und da ist x86 bei Skalaren neutral.

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


Lesenswert?

Peter II schrieb:
> warum sollte auf einem x68 64bit schneller als 8bit sein?

Bei der hier im Thread erfolgten Verwendung als Array-Index entsteht 
zusätzlicher Aufwand durch die erforderliche Erweiterung.

von Peter II (Gast)


Lesenswert?

A. K. schrieb:
> Bei der hier im Thread erfolgten Verwendung als Array-Index entsteht
> zusätzlicher Aufwand durch die erforderliche Erweiterung.

bei x86 kann man doch auch 64 und 8 bit addieren. Da muss doch vorher 
nicht erweitert werden.

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> bei x86 kann man doch auch 64 und 8 bit addieren.

Wie?

Ausserdem wird diese Rechnung meist in der Adressierung selbst 
durchgeführt, und die kennt keine 8-Bit Register.

Bei x86-64 sind das trotz 32-Bit int/unsigned 64-Bit Register. Hier 
lässt GCC deshalb 2 Indizes parallel laufen, einer mit 32 fürs Zählen 
und einer mit 64 Bits fürs Adressieren, weil i negativ sein kann:
1
void f(int *a, int b, int n) {
2
        int i;
3
        for (i = b; i < n; ++i)
4
                a[i] += 1;
5
}
Hier hingegen reicht ein Index:
1
void f(int *a, int n) {
2
        int i;
3
        for (i = 0; i < n; ++i)
4
                a[i] += 1;
5
}

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Und da ist x86 bei Skalaren neutral.

Habe ich gerade mal durch einen kleinen selbstgehackten Benchmark auf 
x86-64 (Linux) verifiziert. Du hast recht. Beim x86 ist das tatsächlich 
so. Kenne ich von anderen 32- oder 64-Bit-Plattformen (diverse 
RISC-CPUs) anders.

Ist das der x86-typischen Altlast geschuldet?

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


Lesenswert?

Frank M. schrieb:
> Kenne ich von anderen 32- oder 64-Bit-Plattformen (diverse
> RISC-CPUs) anders.

RISCs haben vom Prinzip her nur Wortoperationen in Registern. Bei 64 Bit 
Architekturen aber u.U. auch noch 32 Bit Operationen, um beim (L)LP64 
Modell (32 Bit int/unsigned) keinen zusätzlichen Aufwand zu bekommen. 
Aber weder 8 noch 16 Bits. ARM hatte Anfangs noch nicht einmal Lade- und 
Speicheroperationen für 16 Bit Typen.

> Ist das der x86-typischen Altlast geschuldet?

Ja. 8086 hatte gleichermassen 8- wie 16-Bit Operationen. Die haben sich 
erhalten, so dass x86-64 gleichermassen mit 8, 16, 32 und 64 Bits 
rechnen kann. Bei der Division kann sich ein kleinerer Type auch sehr 
lohnen und in der Codierung gibts einen kleinen Vorteil bei 8 und 32 
Bits.

Es kann allerdings subtile Laufzeitunterschiede durch die 
Implementierung geben. Etwa wenn ein Prozessor bei Teilwortoperationen 
(8 und 16 Bits) den Rest des Registers mit durch die ALU schiebt und 
sich dabei ggf. falsche Abhängigkeiten einhandelt.

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


Lesenswert?

A. K. schrieb:
> lässt GCC deshalb 2 Indizes parallel laufen, einer mit 32 fürs Zählen
> und einer mit 64 Bits fürs Adressieren, weil i negativ sein kann:

Das war Unsinn. Komplizierter als mit 64-Bit Variablen ist der Code aber 
trotzdem. Zumal er (4.7.2) bei unsigned als Indextyp die implizite 
zero-extension von 32 Bit Operationen nicht optimal nutzt.

: Bearbeitet durch User
von Mikro 7. (mikro77)


Lesenswert?

A. K. schrieb:
> Peter II schrieb:
>> bei x86 kann man doch auch 64 und 8 bit addieren.
>
> Wie?

Würde mich auch interessieren. Opcode?

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.