Forum: Compiler & IDEs kleines Shift-Problem


von Horst (Gast)


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.

von Walter (Gast)


Lesenswert?

probier mal 0xa9L<<24

von Horst (Gast)


Lesenswert?

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

von Horst (Gast)


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:
1
temp = *array++; + (*array++)<<8 + (*array++)<<16 + (*array)<<24;

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

von holger (Gast)


Lesenswert?

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

Mach mal das Semikolon am Ende der Zeile weg ;)

von Horst (Gast)


Lesenswert?

ach das Semi nach dem ersten "array" .. sorry ist nur hier ein 
Schreibfehler.

es geht sonst auch nicht.

von Horst (Gast)


Lesenswert?

Wenn ich es so mache, stimmen die Variablem tmp1..4. Aber beim 
Zusammenbau auf das 32-Ding bleibt dieses leer.
1
tmp1=(*array++);
2
tmp2=(*array++);
3
tmp3=(*array++);
4
tmp4=(*array);
5
6
temp = tmp1&0xFF + (tmp2&0xFF)<<8 + (tmp3&0xFF)<<16 + (tmp4&0xFF)<<24;

von FBI (Gast)


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:
1
  temp = *(uint32_t*)array;
Ansonsten eventuell so:
1
  temp = (uint32_t)array[0] + (uint32_t)array[1]<<8 + (uint32_t)array[2]<<16 + (uint32_t)array[3]<<24;

CU

von FBI (Gast)


Lesenswert?

Ups da war wer schneller :)

Wie sind denn tmp1-4 definiert?

von Horst (Gast)


Lesenswert?

sind alles "unsigned char"

von holger (Gast)


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;

von Horst (Gast)


Lesenswert?

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

von holger (Gast)


Lesenswert?

Welcher uC ?

von Horst (Gast)


Lesenswert?

mega16 + avrstudio

von Horst (Gast)


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

von holger (Gast)


Lesenswert?

Wie ist array definiert ?

von holger (Gast)


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 ?

von Horst (Gast)


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

von Horst (Gast)


Lesenswert?

nein, sind uint8_t

von holger (Gast)


Lesenswert?

Was ist damit ?

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

von Horst (Gast)


Lesenswert?

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

von holger (Gast)


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.

von Horst (Gast)


Lesenswert?

ok, das macht Sinn. Danke !!

von Matthias (Gast)


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.

von Horst (Gast)


Lesenswert?

Noch eine Erkenntnis:


Dies:
1
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:
1
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.

:-)

von Karl H. (kbuchegg)


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:
>
1
> temp = ((uint32_t)*array++) + (((uint32_t)*array++)<<8) + (((uint32_t) *array++)<<16) + (((uint32_t)*array)<<24);
2
>
> 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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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

von Mark .. (mork)


Lesenswert?

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

MfG Mark

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.