Forum: Compiler & IDEs 16-bit Variable - Wie werden sie gespeichert?


von Christian Q. (osx)


Lesenswert?

Hallo. Ich suche Informationen was passiert, wenn ich eine 16 bit 
Variable auf einem 8 bit Prozessor anlege.
z.B. uint16 x = 42420; /*  1010010010100010 */

Was tut der Prozessor hier? 16bit in eine 8bit Variable schreiben wird 
nicht passen - also muss er 2 8bit Variablen nehmen. Doch wie werden 
diese mit einander bekanntgemacht/verknüpft, dass ich bei der Benutzung 
von x nicht nur den ersten Teil bearbeiten kann.

Kann mir das jemand erklären oder sagen, was für Stichworte hier 
einfallen.

von user (Gast)


Lesenswert?

Der Compiler erzeugt code der auf 16bit funktioniert, er baut zB. eine 
16bit Addition mit 8bit Befehlen.

von Christian Q. (osx)


Lesenswert?

D.h. er weiß, wenn ich x auslese, dass er die Register addiert?
Was steht dann in den Beiden Registern drin bei dem Beispiel 
1010010010100010?

L:10100010
H:10100100
wenn ich die addiere komme ich nicht auf 42420.

von Peter II (Gast)


Lesenswert?

Christian Q. schrieb:
> wenn ich die addiere komme ich nicht auf 42420

ist doch klar. Addieren ist der Falsche weg.

wenn du eine "4" und eine "2" zu einer "42" verbindest, dann musst du 
doch auch nicht addieren.

von Christian Q. (osx)


Lesenswert?

Okay, ich hatte addiert, weil es in dem Satz so stand.
Ist das hier in einem Beitrag hier beschrieben? Konnte es nicht finden.

Wie sieht das auf nem 16bit aus. Dort hat man das Problem nicht oder?

von Peter II (Gast)


Lesenswert?

Christian Q. schrieb:
> Wie sieht das auf nem 16bit aus. Dort hat man das Problem nicht oder?

jain, auch dort ist es in 2x8bit abgelegt. Nur das die ALU damit direkt 
rechnen kann.

von Klaus (Gast)


Lesenswert?

Der Compiler weiß schon, wie er mit 16 Bit Variablen umgehen muß, er 
kann das auch mit noch größeren. Laß ihn einfach machen. Er macht das 
schließlich nicht zum ersten Mal.

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Christian Q. schrieb:
> D.h. er weiß, wenn ich x auslese, dass er die Register addiert?
> Was steht dann in den Beiden Registern drin bei dem Beispiel
> 1010010010100010?
>
> L:10100010
> H:10100100
> wenn ich die addiere komme ich nicht auf 42420.

Du hast als kleiner Christian in der Grundschule das kleine EinmalEins 
gelernt. Oder nicht?
D.h. du hast auswendig gelernt, wieviel 2 + 3 ist, wieviel 8 + 5 ist, 
usw, usw. Für alle einstelligen Zahlen hast du alle Kombinationen 
auswendig gelernt.

Und wie machst du das, wenn du 2-stellige Zahlen addieren sollst?

   13
+  28
  ---
    ?

du wendest deine auswendig gelernten Regeln für die 1-stelligen Zahlen 
an und du hast noch gelernt, wie du mit dem Übertrag von der einen 
Stelle in die nächst höhere umgehen musst.

Die Analogie ist zwar nicht ganz perfekt, aber nenn die Einerstelle 
einfach mal 'Low-Byte' und die Zehnerstelle einfach mal 'High-Byte' und 
du hast genau das Schema, mit dem ein µC '2-stellige' Zahlen addiert, 
obwohl er mit seinen eingebauten Mechanismen nur '1-stellige' Zahlen 
addieren kann. Nur das es im µC eben nicht Einer und Zehner sondern 
8-Bit Zahlen und 16-Bit Zahlen sind. Aber das Prinzip ist genau das 
gleiche: Man zerlegt eine kompliziertere Berechnung (Addition von 16 Bit 
Zahlen) in die Operationen (Addition von 8 Bit Zahlen) die man 
beherrscht samt Vorschriften wie sich Üerträge fortpflanzen bzw. wie man 
aus den Teilergebnissen das Komplettergebnis bekommt. Und mit 8-Bit 
Zahlen kann der µC perfekt umngehen.

von Karl H. (kbuchegg)


Lesenswert?

> Was tut der Prozessor hier? 16bit in eine 8bit Variable schreiben
> wird nicht passen - also muss er 2 8bit Variablen nehmen. Doch wie
> werden diese mit einander bekanntgemacht/verknüpft, dass ich bei
> der Benutzung von x nicht nur den ersten Teil bearbeiten kann.

Das ist kein großes Geheimnis, denn hier

  uint16 x = 42420; /*  1010010010100010 */

hast du ja die Aussage getroffen, dass x aus 16 Bit besteht. Der 
COmpiler muss sich das nur in seine internen Tabellen eintragen und wenn 
du dann x irgendwo benutzt, sieht er in den Tabellen nach und findet 
raus: "Ooops, bei x handelt es sich um eine 16-Bit Einheit. Wenn ich x 
also aus dem Speicher laden muss, dann muss ich 2 hinereinander liegende 
Bytes laden"

Alles nur eine Frage der Buchführung.

von Christian Q. (osx)


Lesenswert?

Okay. Ist nun klar so weit. Danke!

Ich wollte mir das für einen atomic data access veranschaulichen. Manche 
Prozessoren schaffen das Lesen/Schreiben einer 16bit Variable ja in 
einer Maschinenanweisung, andere nicht. D.h. ich muss damit rechnen, 
dass ich eine Variable auslese und genau nach dem ersten von zwei Byte 
ein Interrupt auslöst und die Variable überschreibt. Dann hab ich ein 
riesiges Problem.
Lösung wäre Semaphore oder Mutex denke ich... oder besser das Behälter 
Pattern.

von Peter II (Gast)


Lesenswert?

für soetwas muss man seine Hardware kennen. Auf einem 16bit (oder mehr) 
brauchst du dir darüber keine gedanken zu machen. Bei 8bit schon. Aber 
dort gibt es meist auch keine Mutex oder Semaphore.

Auch ist für soetwas ein Mutex viel zu langsam, wenn es nur ein ein paar 
takte wartezeit geht, verwendet man lieber spin waits.

von Christian Q. (osx)


Lesenswert?

Macht man das wirklich so? Sagt mir jetzt nicht so zu.

von Karl H. (kbuchegg)


Lesenswert?

Christian Q. schrieb:
> Macht man das wirklich so? Sagt mir jetzt nicht so zu.

Auf einem µC der Größenklasse AVR?

Nö. Interrupt aus - 16 Bit Wert geholt - Interrupt ein

Da gibt es ja kein Betriebssystem, mit dem man sich rumstreiten müsste, 
ob man jetzt die Interrupts abschalten darf oder nicht.
Manchmal ist es auch von Vorteil, wenn man alleiniger Herr auf der 
Maschine ist.

von Peter II (Gast)


Lesenswert?

Christian Q. schrieb:
> Macht man das wirklich so? Sagt mir jetzt nicht so zu.

und warum nicht? Wenn es nur um den Zugriff auf eine Variabel geht, dann 
ist es doch sinnlos erst eine Mutex der bis auf Kernel ebene funktionen 
aufruft zu verwenden als selber eine schleife von ein paar takten zu 
drehen.

Meist wird es so gemacht, das man selber ein "paar" Takte aktiv wartet 
und dann auf einen Mutex (oder besser Semaphore ) umschaltet.

Aber welcher 8bit prozessor hat denn ein BS mit Mutex und Semaphoren? 
Ich würde dort einfach die interupts sperren und auf die Variabel 
zugreifen. Dann die IRQ wieder aktivieren.

von Christian Q. (osx)


Lesenswert?

Okay, bin eigentlich im Moment auf nem ARM mit OS unterwegs und dachte 
auch gerade eher an Tasks. 2 verschiedene Welten.
Wobei die Frage eigentlich allgemein war aber mir unterbewusst das 
konsequente Warten aufstieß.

von Karl H. (kbuchegg)


Lesenswert?

Christian Q. schrieb:
> Okay, bin eigentlich im Moment auf nem ARM mit OS unterwegs und dachte
> auch gerade eher an Tasks. 2 verschiedene Welten.
> Wobei die Frage eigentlich allgemein war aber mir unterbewusst das
> konsequente Warten aufstieß.

Immer langsam mit den Jungen Pferden.
Im Regelfall muss da nicht besonders gewartet werden.
Man liest 2 mal hintereinander und wenn die Werte gleich sind, 
akzeptiert man das als Ergebnis. Sind sie nicht gleich, wird eine 
Ehrenrunde eingelegt und ein weiterer Leseversuch drann gehängt und 
erneut verglichen.

Theoretisch kann das jetzt bis zum St. Nimmerleinstag so dahin gehen, 
wenn dein System laufend Interrupts feuert und dabei ständig die 
Variable verändert wird.
Praktisch ist aber beim 3. mal Lesen der stabile Zustand erreicht.

von Klaus (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Auf einem µC der Größenklasse AVR?
>
> Nö. Interrupt aus - 16 Bit Wert geholt - Interrupt ein

Müsste nicht eigentlich der Compiler das erledigen, wenn die Variable 
volatile ist? Wenn er volatile wirklich ernst nimt, kann er sich beim 
Lesen in zwei Teilen eigentlich nicht darauf verlassen, daß die Variable 
sich zwischendrin nicht ändert.

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:
> Karl Heinz Buchegger schrieb:
>> Auf einem µC der Größenklasse AVR?
>>
>> Nö. Interrupt aus - 16 Bit Wert geholt - Interrupt ein
>
> Müsste nicht eigentlich der Compiler das erledigen, wenn die Variable
> volatile ist? Wenn er volatile wirklich ernst nimt, kann er sich beim
> Lesen in zwei Teilen eigentlich nicht darauf verlassen, daß die Variable
> sich zwischendrin nicht ändert.

voltile erfüllt einen ganz anderen Job.
Bei volatile geht es nicht um atomaren Zugriff.

FAQ: Was hat es mit volatile auf sich


(Der C-Standard hat nicht den Hauch einer Ahnung, dass es auch sowas wie 
Interrupts gibt. Dieser ganze Themenkreis, so wie zb auch Multitasking 
ist in der Normierung komplett ausgespart. Heck - der C Standard hat ja 
noch nicht einmal etwas zum Thema Monitor oder Tastatur zu sagen :-)

von Klaus (Gast)


Lesenswert?

Ich habe volatile bisher so verstanden, daß eine Variable von außerhalb 
des aktuellen Programmkontextes geändern werden kann, also z.B. shared 
Memory. Dies wird in einem µC entweder ein Memory mapped Register oder 
ein Interrupthandler sein.

Karl Heinz Buchegger schrieb:
> (Der C-Standard hat nicht den Hauch einer Ahnung, dass es auch sowas wie
> Interrupts gibt :-)

Das ist schon klar, es muß ja nicht ein Interrupt sein, es könnte ja 
auch ein anderer Thread sein, und das ist ja ein reiner C Kontext. Und 
das Problem ist ja nicht auf 8/16 Bit begrenzt, es verschiebt sich bei 
32 Bittern nur in Richtung long long.

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:
> Ich habe volatile bisher so verstanden, daß eine Variable von außerhalb
> des aktuellen Programmkontextes geändern werden kann, also z.B. shared
> Memory. Dies wird in einem µC entweder ein Memory mapped Register oder
> ein Interrupthandler sein.

Ja, ist ja auch richtig so.
Aber das ist eine andere Baustelle, die erst mal nichts mit atomarem 
Zugriff zu tun hat.
Auch ein einzelnes Byte kann von ausserhalb verändert werden. Und 
einzelne Bytes können praktisch immer atomar gelesen werden (zumindest 
fällt mir jetzt keine Architektur ein, bei der das nicht so wäre). D.h. 
da ist atomar per Definition kein Thema. Wohl aber volatile, um den 
Zugriff nicht wegzuoptimieren.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Christian Q. schrieb:
> Hallo. Ich suche Informationen was passiert, wenn ich eine 16 bit
> Variable auf einem 8 bit Prozessor anlege.
> z.B. uint16 x = 42420; /*  1010010010100010 */

Du legst die Variable nicht in einem Prozessor an, sondern mit C-Code, 
und dessen Verhalten ist ist im C-Standard oder in der Implementierung 
(Compiler, (E)ABI, etc.) spezifiziert.

Wie sich uint16_t auf der durch den C-Standard beschriebenen abstrakten 
Maschine verhält steht in C99, das uint16_t einführt.

Für das Verhalten auf der konkreten Maschine musst du das ABI studieren, 
wo Dinge eingehen wie Alignment, Endianess, Type Promotion, etc.  Für 
AVR etwa:

http://gcc.gnu.org/wiki/avr-gcc#ABI

von Rolf Magnus (Gast)


Lesenswert?

Klaus schrieb:
> Ich habe volatile bisher so verstanden, daß eine Variable von außerhalb
> des aktuellen Programmkontextes geändern werden kann, also z.B. shared
> Memory. Dies wird in einem µC entweder ein Memory mapped Register oder
> ein Interrupthandler sein.

Richtig. Aber der Compiler weiß nicht, wodurch konkret die 
volatile-Variable in einem bestimmten Kontext verändert wird. Wie sollte 
er also Code erzeugen, der davor wirksam schützt? Das Sperren von 
Interrupts bringt ja nichts, wenn die Änderung gar nicht durch eine ISR 
erledigt wird.

von Klaus (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Das Sperren von
> Interrupts bringt ja nichts, wenn die Änderung gar nicht durch eine ISR
> erledigt wird.

Wo du recht hast, haste recht.

MfG Klaus

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.