www.mikrocontroller.net

Forum: Compiler & IDEs kleines Shift-Problem


Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich weis grad nicht, warum er das net macht: ich will eine 8Bit Zahl in 
eine 32Bit Zahl ganz nach links schieben.

uint32_t temp=0;
temp = ((0xa9)&0x000000FF)<<24

Aber im Debugger/Simulator ist nach dieser OP die Variable 'temp' immer 
(noch) Null.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
probier mal 0xa9L<<24

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke das geht.
ISt aber komisch warum das andere nicht funzt. Es ist ein Code von einem 
anderen Compiler, der dort funkioniert.

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
im Weiteren will ich das folgende realisieren:

Ich habe ein Array mit 4 Zellen (jedes 1 Byte)

Nun sollen diese 4 Byte hintereinander in eine 32-Bit Variable.
Ich muss aber mit Zeigern drauf zugreifen. So ist es bis jetzt:
temp = *array++; + (*array++)<<8 + (*array++)<<16 + (*array)<<24;

Da muss ein Fehler drin sein. Hab aber schon rumprobiert.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>temp = *array++; + (*array++)<<8 + (*array++)<<16 + (*array)<<24;
>temp = *array++;

Mach mal das Semikolon am Ende der Zeile weg ;)

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach das Semi nach dem ersten "array" .. sorry ist nur hier ein 
Schreibfehler.

es geht sonst auch nicht.

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich es so mache, stimmen die Variablem tmp1..4. Aber beim 
Zusammenbau auf das 32-Ding bleibt dieses leer.
tmp1=(*array++);
tmp2=(*array++);
tmp3=(*array++);
tmp4=(*array);

temp = tmp1&0xFF + (tmp2&0xFF)<<8 + (tmp3&0xFF)<<16 + (tmp4&0xFF)<<24;


Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

auf jeden Fall ist da bei Dir ein Semikolon zu viel :)
Falls das Byteordering stimmt, reicht ja vielleicht auch einfach ein 
Typecast für den Zeiger:
  temp = *(uint32_t*)array;
Ansonsten eventuell so:
  temp = (uint32_t)array[0] + (uint32_t)array[1]<<8 + (uint32_t)array[2]<<16 + (uint32_t)array[3]<<24;

CU

Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups da war wer schneller :)

Wie sind denn tmp1-4 definiert?

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sind alles "unsigned char"

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>temp = *array++; + (*array++)<<8 + (*array++)<<16 + (*array)<<24;

BIG_ENDIAN oder LITTLE_ENDIAN ?

Drehs mal um

temp = ((unsigned long)*array++)<<24 + ((unsigned long)*array++)<<16 + 
((unsigned long)*array++)<<8 + *array;

Besser ?

Oder doch lieber

temp = *array++ + ((unsigned long)*array++)<<8 + ((unsigned 
long)*array++)<<16 + ((unsigned long)*array)<<24;

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
da sProblem muss woanders liegen. selbst wenn ich keine Pointer benutze, 
nur Zahlen, assembliert der die nicht in die 'temp'

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welcher uC ?

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mega16 + avrstudio

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
noch zwei Diagnosen:

[c]
tmp1=1;
tmp2=2;
temp = (tmp1<<8) + tmp2;
{/c]
Ergebnis: temp=0x00000102



[c]
tmp1=1;
tmp2=2;
temp = (tmp1<<16) + tmp2;
{/c]
Ergebnis: 0x00000002

Warum mag er keine Shift über 16 Bit ??

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ist array definiert ?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bevor sich hier alle den Mund fusselig reden:

Achte auf deine Datentypen !

>tmp1=1;
>tmp2=2;
>temp = (tmp1<<16) + tmp2;

Ist tmp1 ein unsigned long ?

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi holger,
das Problem scheint was mit dem Shift zu sein.
bis 15Bit schiebt er, danach ist immer Null.
Also die komplette linke Hälfte der 32-Bit-Variable ist stets Null

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nein, sind uint8_t

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist damit ?

temp = ((unsigned long)tmp1<<16) + tmp2;

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
alles klar, mit "long" gehts.
Versteh ich aber nicht, warum das sein muss.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst eine 8 Bit Variable nicht um 16 Bits nach links schieben.
Spätestens nach 8 Bits sind nur noch Nullen drin.

Also immer erst typecast auf den BENÖTIGTEN Variablentyp
bevor du schiebst.

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, das macht Sinn. Danke !!

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem ist, dass er den 8Bit Typ shiftet, Und wenn man dann um mehr 
als 7 Bit shiftet, kommt eben automatisch 0 raus.

Du brauchst erst einen Typecast auf eine 32Bit Variable. Danach kannst 
du shiften.
Also tmp1 bis tmp4 als unsigned long definieren, wie schon gesagt wurde.

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine Erkenntnis:


Dies:
temp = ((uint32_t)*array++) + (((uint32_t)*array++)<<8) + (((uint32_t)*array++)<<16) + (((uint32_t)*array)<<24);
funktioniert nicht, da der Compiler die "++" wohl nicht hinternander 
ausführt, wie man denken mag, sondern einmal und dann 4 mal kopiert. Ich 
hatte damit immer das erste array-Byte viermal hinternander in "temp"

Folglich bleibt nur o.g. Methode:
temp = ((uint32_t)array[0]) + (((uint32_t)array[1])<<8) + (((uint32_t)array[2])<<16) + (((uint32_t)array[3])<<24);

oder man schreibt die 4 Schritte untereinander als separate Befehle.

:-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> das Problem scheint was mit dem Shift zu sein.

Das Problem ust vielmehr, dass du, Horst, dir endlich
mal ein vernünftiges Buch über C reinziehen solltest,
anstatt durch 'Try und Error' deine C-Kenntnisse
zu erweitern.
Beide Probleme, die du hier ansprichst sind nun wahrlich
alte Hüte in C.

> Dies:
>
> temp = ((uint32_t)*array++) + (((uint32_t)*array++)<<8) + (((uint32_t) *array++)<<16) + (((uint32_t)*array)<<24);
> 
> funktioniert nicht, da der Compiler die "++" wohl nicht hinternander
> ausführt,

Dies funktioniert sehr wohl, aber nicht so wie du das erwartest.
Der Punkt ist: Mit einer Anweisung wie der da, kann der Compiler
machen was er will. Diese Anweisung hat auf jeden Fall undefiniertes
Verhalten, und es wird vom C-Sprachstandard keinerlei bestimmtes
Verhalten gefordert. Kurz gesagt: Eine Variable darf in einem
Ausdruck nur einmal einen neuen Wert bekommen. Dein Ausdruck
versucht aber in ein und demselben Ausdruck array 4-mal einen
neuen Wert zuzuweisen -> undefiniertes Verhalten. Alles mögliche
kann passieren.

Und das arithmetische Berechnungen immer im Zahlenbereich int
stattfinden (es sei denn einer der beteiligten Operanden hat
einen höheren Datentyp), sollte sich auch schon rumgesprochen
haben. Dabei ist es dem Compiler sche...egal, welchen Datentyp
die Variable hat, dem das Ergebnis zugewiesen wird. Während
der Berechnung des Ausdrucks gelten nur die Datentypen die
innerhalb des Ausdrucks vorkommen. Erst nachdem das Ergebnis
berechnet wurde, erfolgt die Anpassung auf die Zielvariable.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Horst wrote:

> ISt aber komisch warum das andere nicht funzt. Es ist ein Code von einem
> anderen Compiler, der dort funkioniert.

Wenn es eine 32-bit-Umgebung ist: kein Problem.  Beim AVR lebst du
aber (C-mäßig) in einer 16-bit-Umgebung.

Übrigens: egal, wie viele Nullen du vor die FF schreibst, die Zahl
bleibt 16-bittig: 0xff, 255, 0x00ff und 0x000000ff sind alle dasselbe.
Wenn sie 32-bittig werden soll, musst du entweder besagten typecast
schreiben, oder den Suffix UL (groß oder klein geschrieben) dranhängen.
C ist hier etwas trickreich: die Konstante 0xffffff würde automatisch
als 32-bittig erkannt (da sie den Wertebereich des 16-bit-Integers
überschreitet).

Autor: Mark .. (mork)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso macht ihr das nicht einfach so:
temp=*(uint32_t*)(array);

MfG Mark

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.