Forum: Compiler & IDEs Beschränkung bei den Schiebebefehlen?


von Nobi (Gast)


Lesenswert?

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.

von Nobi (Gast)


Lesenswert?

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 ;)

von Jan M. (mueschel)


Lesenswert?

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.

von Nobi (Gast)


Lesenswert?

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.

von Jan (Gast)


Lesenswert?

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.

von Nobi (Gast)


Lesenswert?

das ist doch schonmal etwas. ich danke dir. man lernt eben nie aus. ;)

ne gute nacht wünsche ich.

von Joerg X. (Gast)


Lesenswert?

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.

von A.K. (Gast)


Lesenswert?

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.

von Nobi (Gast)


Lesenswert?

ich danke euch. werde gleich mal den neuen code testen.

p.s. rechtsschieben geht um nen wert größer 8 geht hingegen einwandfrei.

von Nobi (Gast)


Lesenswert?

@Joerg.X

klasse sache. da hätte ich auch drauf kommen können ;)
klappt super. danke nochmal.

von A.K. (Gast)


Lesenswert?

> 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.

von Roland P. (pram)


Lesenswert?

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
}

von Joerg X. (Gast)


Lesenswert?

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!

von Roland P. (pram)


Lesenswert?

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

von A.K. (Gast)


Lesenswert?

> Da A.K sagt, dass Shifts nur bis 15 Bit definiert sind

Die Shiftcount wohlgemerkt, die nicht Datenbreite!

von A.K. (Gast)


Lesenswert?

Und bei uint32_t ist man bei der Shiftcount konsequenterweise bis 31 auf 
der sicheren Seite.

von Nobi (Gast)


Lesenswert?

@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
Noch kein Account? Hier anmelden.