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.
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.
in der Tat, auf den ersten Blick sehr merkwürdig :(
1
uint32_tmessage=0x12345678;
2
uint8_teid_string[9];
3
4
voideid_convert(void)
5
{
6
// uint32_t puff2;
7
uint8_tpuff2;
8
unsignedcharn,i=7;
9
unsignedcharStelle_[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.
> 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.
* 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:
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
@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.