Ich habe zwei einzelne Byte und moechte nun ein 16 bit int draus machen. sowas gibts bei ADCL und ADCH z.B.
Hi
1 | uint16_t u16; |
2 | uint8_t u8_low; |
3 | uint8_t u8_high; |
4 | |
5 | u16 = u8_high * 256 + u8_low; |
Matthias
uint16_t make_u16(uint8_t high_byte, uint8_t low_byte) { return ( ((uint16_t)high_byte)<<8 | low_byte) }
binärsystem: x*(2^1) == x<<1 x*(2^2) == x<<2 x*(2^3) == x<<3 dezimalsystem: x*(10^1) == x<<1 usw...
Simon schrieb: > würde eine Union so aussehen? > > union u16 { char a; char b;} ; nein, eher so: union blah { uint16_t als_int; struct { uint8_t ein_byte; uint8_t nochn_byte; } als_bytes; }; union blah test; test.ein_byte = 0x42; test.nochn_byte = 0x23; uint16_t irgend_nen_int = test.als_int;
aber bedenke, das einfachste wurde schon von matthias und ad-rem genannt...
Es ist IMHO nicht garantiert, dass in einer union die Variablen auf fortlaufenden Speicheradressen abgebildet werden. Hängt vom Compiler ab.
wobei shiften und multiplizieren nicht besonders effizient sind, wenn es öfter gemacht wird. Schneller ist die Geschichte mit der union. Falls es schnell gehen soll und die union zu unpraktisch erscheint, dann geht es auch so:
1 | uint16_t ergebnis; |
2 | uint8_t daseinebyte, dasanderebyte; |
3 | ...
|
4 | ((uint8_t*)&ergebnis)[0] = daseinebyte; |
5 | ((uint8_t')&ergebnis)[1] = dasanderebyte; |
Klaus Wachtler schrieb: > wobei shiften und multiplizieren nicht besonders effizient sind, > wenn es öfter gemacht wird. so? shift und oder hat der avr in hardware. das geht auch in 16bit schnell.
pete77 hat auch was wichtiges gesagt, bei gcc sollte man deswegen auch das ganze mit __attibute__((packed)) machen...
Pete K. schrieb: > Es ist IMHO nicht garantiert, dass in einer union die Variablen auf > fortlaufenden Speicheradressen abgebildet werden. Hängt vom Compiler ab. Die Elemente einer union sind eh nicht auf fortlaufenden Adressen, höchstens die der struct.
Der Shift um 8 wird sowieso nicht direkt in Assemblercode umgesetzt. Union Methode und Shift Methode werden vermutlich genau gleich implementiert.
unsigned char byteL, byteH; unsigned short i; i = (byteH << 8) + byteL; > Die Elemente einer union sind eh nicht auf fortlaufenden Adressen, > höchstens die der struct. dafür gibts doch das Attribut packed, oder?
Nils S. schrieb:
> i = (byteH << 8) + byteL;
vorsicht, das muss nicht klappen! dein byteH musst du casten, sonst
schiebst du aus deinem speicherbereich raus.
auf dem avr klappt das vermutlich, weil er bei einem shift um größer 7
sowieso weiteren speicher braucht und der compiler den bereitstellt.
auf anderen architekturen muss das nicht so ein.
Michael M. schrieb: > Nils S. schrieb: >> i = (byteH << 8) + byteL; > vorsicht, das muss nicht klappen! dein byteH musst du casten, sonst > schiebst du aus deinem speicherbereich raus. Da wird nach Standard C nichts "rausgeschoben" und muss nichts gecastet werden. Und zwar gleich aus 2 Gründen, die der Standard vorgibt: - der rechte Operand von << ist ein Integer, also muss das Ergebnis mindestens Integer sein - kleinere Werte als int werden automatisch zu int (integer promotion), bevor sie verrechnet werden. Über die Sinnhaftigkeit dieser Regel kann man sich bei so kleinen CPUs lange unterhalten und es gibt gute Argumente dagegen. Ich habe eine gute Ausrede: Es ist Vorschrift.
Du wolltest den Beweis sicher antreten und hast nur vergessen, ihn anzuhängen.
> Michael M. schrieb > > Hc Zimmerer schrieb: > > [ käse] > sicher nicht auf dem avr-gcc... Hier sollte eine Quelle angegeben werden, falls der C-Standard von avr-gcc an dieser Stelle verletzt wird. Meines Erachtens ist's genauso, wie Hc schreibt. An was sollte sich ein C-Compiler denn bei der Auswertung von Ausdrücken halten? Reiner
integer (16bit) promotion auf einer 8-bit architektur macht keinen sinn. und der rechte operad vom shift ist kein int (16 bit integer), sondern ein char (8 bit integer).
Michael M. schrieb: > integer (16bit) promotion auf einer 8-bit architektur macht keinen sinn. Ist aber trotzdem so bei dem AVR-GCC. > und der rechte operad vom shift ist kein int (16 bit integer), sondern > ein char (8 bit integer). Zahlenkonstanten sind immer integers.
> An was sollte sich ein C-Compiler denn bei der > Auswertung von Ausdrücken halten? Na, an Michael selbstverständlich.
Michael M. schrieb: > integer (16bit) promotion auf einer 8-bit architektur macht keinen sinn. > und der rechte operad vom shift ist kein int (16 bit integer), sondern > ein char (8 bit integer). [ ] Du hast Ahnung davon, was der C-Standard von einem Compiler fordert damit er als C-Compiler gilt [ ] Du weißt vielleicht nicht, dass C eine Sprachdefinition hat und nicht jeder dahergelaufene Compilerbauer seine Sprache so implementieren kann wie er möchte und das Ganze dann "C" nennen kann. [ ] Du hast deinen K&R aufmerksam gelesen und festgestellt, dass in C zwar manches (vieles) dem Compilerbauer freigestellt ist, es aber trotzdem ein paar grundlegende Dinge gibt, an die er sich halten muss.
Michael M. schrieb: > integer (16bit) promotion auf einer 8-bit architektur macht keinen sinn. Nicht alles, was der C-Standard vorschreibt, macht auf allen Architekturen Sinn (und ich habe die Sinnhaftigkeit auch erwähnt). Die GCC-Familie inklusive avr-gcc hält sich daran. > und der rechte operad vom shift ist kein int (16 bit integer), sondern > ein char (8 bit integer). Ein Buch über C hilft hier doch sehr, es muss nicht mal der Standard sein. Das Literal "8" ist ein int. __ (Und immer noch hast Du keinen Beweis geliefert, sondern nur weitere Behauptungen.)
Simon K. schrieb: > Michael M. schrieb: >> integer (16bit) promotion auf einer 8-bit architektur macht keinen sinn. > Ist aber trotzdem so bei dem AVR-GCC. warum wird mein code dann größer, wenn ich beim typedef aus meinem int8_t ein int mache?
Hc Zimmerer schrieb: >> An was sollte sich ein C-Compiler denn bei der >> Auswertung von Ausdrücken halten? > > Na, an Michael selbstverständlich. wär mir auch lieber ^^
Michael M. schrieb: > Simon K. schrieb: >> Michael M. schrieb: >>> integer (16bit) promotion auf einer 8-bit architektur macht keinen sinn. >> Ist aber trotzdem so bei dem AVR-GCC. > warum wird mein code dann größer, wenn ich beim typedef aus meinem > int8_t ein int mache? Das kann man erst beantworten, wenn man den Code sieht. Auch wenn die C-Regeln grundsätzlich die int-Promotion vorsehen, heißt das noch lange nicht, dass ein Compiler sie nicht auch wieder rauswerfen darf, wenn er beweisen kann, dass sich durch den Wegfall der Promotion nach int nichts ändert. Das heißt aber nicht, dass die int-Promotion grundsätzlich nicht gilt. Das heißt nur, dass ein Optimizer die eigentlich vorhandene Promotion weglassen kann, weil sie auf das Ergebnis keinen Einfluss hat. Wenn der Optimizer sich die Sache ansieht und zb. feststellt, dass das Ergebnis in einer 8-Bit Variablen gespeichert wird, kann er den Code rückwärts verfolgen und alle High-Byte Manipulationen, die der eigentliche Compiler eingefügt hat, wieder rauswerfen, weil sie im Ergebnis nicht auftauchen.
alles klar. danke für die aufklärung. da lag ich wohl daneben. entschuldigung.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.