Beschränkung bei den Schiebebefehlen?

Gast #535348
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.
#535380
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.
Gast #535383
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.
Gast #535386
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.
Gast #535388
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.
Gast #535405
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.
Gast #535443
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.
#535452
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
}
#535455
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
Gast #535500
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren