ich wünschen einen schönen abend. ist jemanden eine beschränkung bei der schiebefunktion in c bekannt? hier erstmal ein stück meines quellcodes. ist zwar nicht schön, aber dafür selten ;) uint32_t message = 0x12345678; void eid_convert(void) { uint32_t puff2; unsigned char n, i=7; unsigned char Stelle_[9], eid_string[9]; for (n=0; n<8; n++) { puff2 = message; puff2 &= 0x0000000F << 4*n; puff2>>= 4*n; Stelle_[n] = (uint8_t) puff2; if(Stelle_[n] <= 0x09) { Stelle_[n] = Stelle_[n] + 0x30; } else { Stelle_[n] = Stelle_[n] + 0x37; } eid_string[i] = Stelle_[n]; i--; } eid_string[8]=0x00; i=7; } zur erklärung. ich möchte den 32bit wert, der in message gespeichert ist, für eine lcd ausgabe entsprechend umformen (sprint wollte ich nicht nehmen). daher muss ich jede einzelne stelle separat verarbeiten. diese versuche ich nun mittels 0x0000000F << 4*n; auszumaskieren. das funktionniert auch bis einschließlich n=2 tatellos. doch ab n=3 spielt der code verrückt. bei n=3 sollte eigentlich folgendes geschehen: puff2 &= 0x0000F000; und damit der wert 0x00005000 in puff2 stehen, aber das was drin steht ist 0x12345000. ab n=4 stehen dann nur noch nullen drin. ich habe hier im forum schonmal was zu diesem problem gefunden, doch leider war der lösungslink defekt. also wenn mir jemand ne umgehung dieser möglichen beschränkung nennen kann, so wäre ich sehr dankbar. nun denn, ich sage schonmal danke.
bevor ich es vergesse, ja ich weiß, dass linksschieben um ein der multiplikation mit 2^n entspricht. also mir nicht gleich den kopf runterreißen ;)
Ja, avr-gcc verhält sich "interessant". Er macht die Schieberei nur in 16 Bit und setzt die restlichen Bits auf den gleichen Wert wie Bit 15. Das passt zu dem von dir beschriebenen Verhalten. Eine Lösung, wie dein Code ohne größere Änderung funktionieren könnte, habe ich nicht - aber mit etwas pointer-casten ist das zwar hässlich und unschön, aber in Griff zu bekommen.
danke dir. genau das wollte ich verhintern. interessant ist auch, das avr-gcc 0x0000000F * 0x00001000 genauso behandelt, 0x0000000F * var (wobei var gleich 0x00001000 ist) mir richtig berechnet. kenntst du zufällig den exponent befehl auswendig, sodaß ich ne zahl hoch ne zahl rechnen kann (und die passende *.h-datei). die math.h schien auf den ersten blick sowas nicht anzubieten.
Sorry, kann es jetzt nicht mehr ausprobieren, aber das sollte helfen: das 0x0000000F casten auf (uint32_t). (0x0000000FUL bzw. 15UL macht das selbe) Zahlen werden immer als int angenommen, sofern nichts anderes angegeben ist bzw. offensichtlich ist.
das ist doch schonmal etwas. ich danke dir. man lernt eben nie aus. ;) ne gute nacht wünsche ich.
in der Tat, auf den ersten Blick sehr merkwürdig :(
1 | uint32_t message = 0x12345678; |
2 | uint8_t eid_string[9]; |
3 | |
4 | void eid_convert(void) |
5 | {
|
6 | // uint32_t puff2;
|
7 | uint8_t puff2; |
8 | unsigned char n, i=7; |
9 | unsigned char Stelle_[9]; |
10 | |
11 | |
12 | for (n=0; n<8; n++) |
13 | {
|
14 | // puff2 &= (uint32_t)(0x0F << (4*n));
|
15 | // puff2>>= 4*n;
|
16 | // Stelle_[n] = (uint8_t) puff2;
|
17 | |
18 | puff2 = message >> (n*4); |
19 | Stelle_[n] = puff2 & 0x0f; |
20 | |
21 | if(Stelle_[n] <= 0x09) |
22 | {
|
23 | Stelle_[n] = Stelle_[n] + 0x30; |
24 | }
|
25 | |
26 | else
|
27 | {
|
28 | Stelle_[n] = Stelle_[n] + 0x37; |
29 | }
|
30 | |
31 | eid_string[i] = Stelle_[n]; |
32 | |
33 | i--; |
34 | }
|
35 | |
36 | eid_string[8]=0; |
37 | i=7; |
38 | }
|
Ich hab das mal umgestellt (um die 32Bit rechnerei zu vermeiden) und so geht's wohl, erfüllt den gleichen Zweck (im Simulator getestet; mit -O0 und -Os), erlärt aber nichts.
So merkwürdig ist das nicht, jedenfalls nicht auf einer 8/16-Bit-Maschine, auf der "0x0000000F << 4*n" eine 16bit-Operation und das Verhalten ab n=4 folglich undefiniert ist. Häufiges Missverständnis: Der Datentyp auf der linken Seite einer Zuweisung (hier: puff2) hat keinerlei Auswirkung darauf, mit welcher Datenbreite eine Rechung auf rechten Seite stattfindet. Erst das Endergebnis auf der rechten Seite wird dann in den linken Type umgewandelt.
ich danke euch. werde gleich mal den neuen code testen. p.s. rechtsschieben geht um nen wert größer 8 geht hingegen einwandfrei.
@Joerg.X klasse sache. da hätte ich auch drauf kommen können ;) klappt super. danke nochmal.
> rechtsschieben geht um nen wert größer 8 geht hingegen einwandfrei.
Auch hier ist jedoch Vorsicht geboten. Bei 16-bit Rechnung sind nur
Shifts bis 15 gesichert, alles darüber ist letztlich undefiniert. C
definiert zwar m.E. bis 16, aber die normative Kraft des Faktischen
[x86] macht schon vorher schlapp.
Hi, sowas kostet oft* extrem Zeit:
1 | puff2 = message >> (n*4); |
* in dem Fall wohl nicht, da mit 4 multipliziert wird und der Compiler das teilweise wegoptimiert. ich würde aber dennoch folgende kleine Optimierung vorschlagen:
1 | uint32_t message = 0x12345678; |
2 | uint8_t eid_string[9]; |
3 | |
4 | void eid_convert(void) |
5 | {
|
6 | uint32_t puff2=message; // zwischenspeichern |
7 | unsigned char i; |
8 | unsigned char Stelle; |
9 | |
10 | |
11 | i = 8; |
12 | do
|
13 | {
|
14 | i--; |
15 | Stelle = (puff2 & 0x0f) | 0x30; // letzten 4 Bit + 0x30 |
16 | if(Stelle > 0x39) Stelle += 0x07; |
17 | puff2 >>= 4; // shiften für nächsten Run |
18 | eid_string[i] = Stelle; |
19 | } while (i > 0) |
20 | |
21 | eid_string[8]=0; |
22 | |
23 | }
|
danke für die Einsichten A.K. ! dann muss ich mir in Zukunft mehr Gedanken um "große" Konstanten machen ;) plötzlich ergeben "xxxL" und "...U" sinn. gruß an alle!
Nachtrag: Da A.K sagt, dass Shifts nur bis 15 Bit definiert sind, machst aus puff2 >>= 4; besser puff2 /= 16; Es steht zwar da auch eine Division da, je nach Optimierungsstufe wird das aber vom Compiler wegoptimiert und du bist garantiert auf der "sicheren Seite" Gruß Roland
> Da A.K sagt, dass Shifts nur bis 15 Bit definiert sind
Die Shiftcount wohlgemerkt, die nicht Datenbreite!
Und bei uint32_t ist man bei der Shiftcount konsequenterweise bis 31 auf der sicheren Seite.
@all diese versteckten restriktionen. gibts da eigentlich ne übersicht über diese dinge, ohne die gcc referenz auseinandernehmen zu müssen? nun bei mir funzt es jetzt mit hilfe von joerg. das mit UL etc. wollte nicht wirklich so wie ich wohl will, sondern hat das nur bis 8bit gemacht. @roland man, man, man. da haste ja meinen code ganz schön optimiert ;) muss ich erstmal durchsteigen und gucken obs so klappt. aber trotzdem danke für die hilfe. und das mit /= ist auch ne möglichkeit. jetzt wo ich weiß, dass das rechtsschieben größer 16 auch nur durch zufall bei mir geklappt hat, werde ich das wohl auch so machen.
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.