www.mikrocontroller.net

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


Autor: Nobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;)

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nobi (Gast)
Datum:

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

ne gute nacht wünsche ich.

Autor: Joerg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
in der Tat, auf den ersten Blick sehr merkwürdig :(
uint32_t message = 0x12345678;
uint8_t eid_string[9];

void eid_convert(void)
{
//  uint32_t puff2;
  uint8_t puff2;
    unsigned char n, i=7;
    unsigned char Stelle_[9];


    for (n=0; n<8; n++)
    {
//    puff2 &= (uint32_t)(0x0F << (4*n));
//    puff2>>= 4*n;
//    Stelle_[n] = (uint8_t) puff2;

      puff2  = message >> (n*4);
      Stelle_[n] = puff2 & 0x0f;

      if(Stelle_[n] <= 0x09)
      {
        Stelle_[n] = Stelle_[n] + 0x30;
      }

      else
      {
        Stelle_[n] = Stelle_[n] + 0x37;
      }

      eid_string[i] = Stelle_[n];

      i--;
    }

  eid_string[8]=0;
  i=7;
}
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.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich danke euch. werde gleich mal den neuen code testen.

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

Autor: Nobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Joerg.X

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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Roland Praml (pram)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, sowas kostet oft* extrem Zeit:
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:
uint32_t message = 0x12345678;
uint8_t eid_string[9];

void eid_convert(void)
{
    uint32_t puff2=message; // zwischenspeichern
    unsigned char i;
    unsigned char Stelle;


    i = 8;
    do
    {
      i--;
      Stelle = (puff2 & 0x0f) | 0x30; // letzten 4 Bit + 0x30
      if(Stelle > 0x39)  Stelle += 0x07;
      puff2  >>= 4; // shiften für nächsten Run
      eid_string[i] = Stelle;
    } while (i > 0)

  eid_string[8]=0;

}

Autor: Joerg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Roland Praml (pram)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Da A.K sagt, dass Shifts nur bis 15 Bit definiert sind

Die Shiftcount wohlgemerkt, die nicht Datenbreite!

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und bei uint32_t ist man bei der Shiftcount konsequenterweise bis 31 auf 
der sicheren Seite.

Autor: Nobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.