mikrocontroller.net

Forum: PC-Programmierung 4 Byte Array in long umwandeln


Autor: Timur Yigit (smokingslim)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Cracks ich hab da ein Anfänger Problem.

Ich bekomme von einem yC 4 einzelne Byte zugeschickt die aber einen 
32Bit Wert darstellen also wollte ich die einzelnen Bytes in Array 
Packen dann hab ich denn 32 Bit wert.
Mein Problem ist wie kann ich dieses Array in einen long umwandeln damit 
ich damit rechnen kann.

Danke

Autor: Magnus Müller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Programmiersprache?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mein Problem ist wie kann ich dieses Array in einen long umwandeln
> damit ich damit rechnen kann.
long value = (unsigned long)(byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3];
    printf("Value is %x\n", value);

Je nach Byteorder der ankommenden Daten müssen die Bytes evtl. umgekehrt 
werden.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder mit Referenzierung/Dereferenzierung in einem Schritt:
Klappt aber nur, wenn die Endieness stimmt :)
long value = *(long*)&Array[0];

  

Autor: Timur Yigit (smokingslim)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah sorry die Sprache ist C.
Diese Lösung ist mir auch schon eingefallen allerding sind das ja über 
50 Rechenoperationen das müsste doch mit Arrays oder Pointern eleganter 
gehen.

Autor: Timur Yigit (smokingslim)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
long value = *(long*)&Array[0];

Ich habe mich jetzt mal ein bischen in die PointerGeschichte eingelesen 
aber diese Anweisung versteh ich gar nicht. Wo wird denn gezeigt das der 
Wert Array[x] an die richtige stelle in dem long abgelegt wird.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Array aus vier 8-Bit Variablen belegt im Speicher vier 
aufeinanderfolgende Bytes. Eine long-Variable belegt im Speicher vier 
aufeinanderfolgende Bytes.

Also ist es möglich, den Speicher bedarfsorientiert "anders" zu 
interpretieren, allerdings ist hier die Interpretation 
implementierungsabhängig, was an der "endianness" des Prozessors liegt.

Ein Array { 0x12, 0x34, 0x56, 0x78 } wird auf little-Endian-Prozessoren 
(u.a. Intel) als Long-Wert 0x78563412 interpretiert, auf 
big-Endian-Prozessoren (u.a. Motorola) hingegen als 0x12345678.



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

Bewertung
0 lesenswert
nicht lesenswert
Timur Yigit wrote:
> long value = *(long*)&Array[0];
>
> Ich habe mich jetzt mal ein bischen in die PointerGeschichte eingelesen
> aber diese Anweisung versteh ich gar nicht. Wo wird denn gezeigt das der
> Wert Array[x] an die richtige stelle in dem long abgelegt wird.

gar nicht, das wird vorher schon gemacht
  unsigned char Array[4];

  Array[0] = erster_Wert_den_du bekommst;
  Array[1] = zweiter_Wert_den_du_bekommst;
  Array[2] = dritter_Wert_den_du_bekommst;
  Array[3] = vierter_Wert_den_du_bekommst;

  long value = *(long*)Array;

Der Trick besteht darin, dass bei einem Array die 4
Bytes im Speicher hintereinander abgelegt werden und
ein long ebenfalls aus 4 Bytes besteht.

Die letzte Anweisung, die mit dem Cast, sagt nichts
anderes als:
  * nimm die Startadresse des Arrays
    Array

  * und tu mal so, als ob diese Adresse die Adresse eines
    long wäre
    (long*)Array

  * von dieser angenommenen long-Adresse holst du jetzt
    mal den long Wert.
    *(long*)Array

Im Grunde trickst man den Compiler dahin, dass er die 4 Bytes
des Arrays als long auffasst und als long weiterbehandelt.


Allerdings muss die Reihenfolge der Bytes stimmen. Ob also
die Reihenfolge erster_Wert_..., zweiter_Wert_... etc.
richtig ist oder umgedreht werden muss, hängt davon ab in welcher
Reihenfolge der Sender die Bytes schickt und in welcher Reihenfolge
der Empfänger sie haben muss, damit wieder der korrekte Wert
herauskommt.

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

Bewertung
0 lesenswert
nicht lesenswert
Timur Yigit wrote:
>>
>> long value = (unsigned long)(byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3];
>> 

> Diese Lösung ist mir auch schon eingefallen allerding sind das ja über
> 50 Rechenoperationen

Dann hast du den Optimizer deines Compilers nicht eingeschaltet.
Das sollten nicht wesentlich mehr als 4 Operationen sein, die
allesamt Register-Ladeoperationen sind.


Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit der Pointer-Geschichte ist es auf einem 32Bit Rechner nur eine 
32-Bit Lade-Operation.

Autor: Timur Yigit (smokingslim)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super Danke das habe sogar ich verstanden.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Diese Lösung ist mir auch schon eingefallen allerding sind das ja über
> 50 Rechenoperationen

Also bei mir sind es eher so 10 rum, was zugegebenermaßen immer noch 
lange nicht so gut ist, wie ich erwartet hätte. Aber machen dir wirklich 
50 Rechenoperationen pro per serieller Schnittstelle empfangenem Wert 
sorgen? Es ist eher unwahrscheinlich, daß das einen meßbaren Unterschied 
in der Prozessorauslastung macht.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wäres hiermit ???

union Converter
{
  long  lData;       // complete data
        char  cData[4];      // Data packages
}Switch;

//Z.B.:

Switch.lData = 0x12979898;

// Zugriff
x = Switch.cData[0]

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sowas darf man nach C-Konvention nicht, bzw. das Ergebnis kann sich von 
Compiler zu Compiler und Zielplattform unterscheiden und hat 
möglicherweise nicht den gewünschten Effekt.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit anderen Worten:

Genau so macht man es.


Und bekommt Haarausfall, wenn man das funktionierende Programm auf eine 
andere Hardware portieren will, weil man diese Stellen auch nicht im 
Quelltext als problematisch oder "hic sunt dracones" gekennzeichnet hat.

Und dann kreischt und flucht man und postet interessante Vermutungen 
über Compilerfehler in irgendwelchen Foren ...

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Diese Lösung ist mir auch schon eingefallen allerding sind das ja
>> über 50 Rechenoperationen
>
> Also bei mir sind es eher so 10 rum, was zugegebenermaßen immer noch
> lange nicht so gut ist, wie ich erwartet hätte.

Folgendes
long value = (unsigned long)(byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3];
ergibt bei mir 16 Bytes Code, aber das falsche Ergebnis, da die 16-
und 24-Bit-Shifts auf int angewandt immer 0 ergeben. Besser:
unsigned long value =
  (unsigned long)byte[0] << 24 |
  (unsigned long)byte[1] << 16 |
  (unsigned int) byte[2] <<  8 |
                 byte[3];
Das braucht aber schon 37 Bytes.

Die Pointer-Methode scheint wohl die Lösung zu sein, wenn es auf
Geschwindigkeit ankommt, sonst würde ich auch eher die Shift-Methode
vorziehen, weil dabei deutlicher wird, welches Byte des Bytestroms zum
High-Byte und welches zum Low-Byte wird.

Autor: MNR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die union Lösung ist genauso gut oder schlecht, wie
long value = *(long*)Array;
 Wenn man Hardware-unabhängig bleiben will, müßte man nur die Indizes 
des Arrays per Macro umsortieren, dann läßt sich das leicht portieren.

Gruß, Matthias

Autor: Christoph __ (chris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MNR wrote:
> Die union Lösung ist genauso gut oder schlecht, wie
long value =
> *(long*)Array;
 Wenn man Hardware-unabhängig bleiben will, müßte man
> nur die Indizes des Arrays per Macro umsortieren, dann läßt sich das
> leicht portieren.

Nein, um portabel zu bleiben musst du mehr machen. Ein char-Array muss 
nicht zwangsweise ausgerichtet sein im RAM. Es gibt aber CPUs, bei denen 
ein long ausgerichtet sein muss, sich also auf einer durch 4 teilbaren 
Adresse befinden muss. Auf so einem Rechner darfst du unter keinen 
Umständen ein nicht ausgerichtetes char-Array nach long casten, sonst 
stürzt das Programm einfach ab. Die Ausrichtung des char-Arrays kannst 
du mit Standard-Mitteln nicht hinbekommen.

Am sichersten ist es daher meiner Meinung nach, die Umwandlung zentral 
zu machen und eine Funktion zu schreiben:
long charsToLong(char blub[4]);

Dann hat man den mglw. unportablen Code wenigstens nur an einer Stelle. 
Ich würde aber dort einfach die Lösung mit bit-shifts nehmen. 
Schließlich geht es hier um ein PC- und nicht ein 
Mikrocontroller-Programm. Bei PC-Programmen spielt in erster Linie die 
Laufzeit-Klomplexität im Sinne der Landau-Notation eine Rolle, weniger 
die tatsächlichen konstanten Laufzeitunterschiede zwischen O(1) und O(1) 
(solange der Faktor nicht in die tausende geht, und je nach Kontext).

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mit anderen Worten:
>
> Genau so macht man es.

Ja, "man" macht viel, was eigentlich falsch ist.

> Und dann kreischt und flucht man und postet interessante Vermutungen
> über Compilerfehler in irgendwelchen Foren ...

Genau so läufts. Aber zum Glück sind wird ja hier und immer zur 
Seelsorge bereit. ;-)


@yalu:

Hast natürlich Recht. Ich weiß auch nicht, was ich dabei gedacht habe. 
Beim ersten Byte habe ich noch dran gedacht, den Cast zu machen, beim 
Rest nicht mehr.

> Besser:
> unsigned long value =
>   (unsigned long)byte[0] << 24 |
>   (unsigned long)byte[1] << 16 |
>   (unsigned int) byte[2] <<  8 |
>                  byte[3];
>
> Das braucht aber schon 37 Bytes.

Was braucht:
unsigned long value = byte[0];
value <<= 8;
value |= byte[1];
value <<= 8;
value |= byte[2];
value <<= 8;
value |= byte[3];

?

Autor: MNR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Chris
Wenn man auch zu diesen CPUs kompatibel sein möchhte, würde man sich ein 
long definieren, und das dann als charArray nutzen. Also z.B. sinngemäß
long l;
char cp[] = &l;
cp[0]= ...

Gruß, Matthias

Autor: Edis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast es hingekriegt oder soll ich vorbeikommen?  ;-)
Gruß Edis

Autor: Edis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat es hingekriegt oder soll ich vorbeikommen? ;-)
Gruß Edis

Autor: Timur Yigit (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ha ne danke ich habs jetzt geschoben damit der coder übertragbar bleibt

tschu

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.