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
Gast
#579161
Programmiersprache?
Gast
#579169
> Mein Problem ist wie kann ich dieses Array in einen long umwandeln > damit ich damit rechnen kann.
1 | |
2 | |
Je nach Byteorder der ankommenden Daten müssen die Bytes evtl. umgekehrt werden.
Oder mit Referenzierung/Dereferenzierung in einem Schritt: Klappt aber nur, wenn die Endieness stimmt :)
1 | |
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.
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.
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.
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
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
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.
Timur Yigit wrote:
>>1 | |
2 | |
> 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.
Mit der Pointer-Geschichte ist es auf einem 32Bit Rechner nur eine 32-Bit Lade-Operation.
Super Danke das habe sogar ich verstanden.
Gast
#579274
> 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.
Gast
#580649
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]
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.
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 ...
Gast
#580723
>> 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
1 | |
ergibt bei mir 16 Bytes Code, aber das falsche Ergebnis, da die 16- und 24-Bit-Shifts auf int angewandt immer 0 ergeben. Besser:
1 | |
2 | |
3 | |
4 | |
5 | |
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.
Gast
#580728
Die union Lösung ist genauso gut oder schlecht, wie
1 | |
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
MNR wrote:
> Die union Lösung ist genauso gut oder schlecht, wie1 | |
2 | |
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).
Gast
#582567
> 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:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
?
Gast
#583243
@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äß
1 | |
2 | |
3 | |
Gruß, Matthias
Gast
#591690
Hast es hingekriegt oder soll ich vorbeikommen? ;-) Gruß Edis
Gast
#591691
Hat es hingekriegt oder soll ich vorbeikommen? ;-) Gruß Edis
Gast
#591768
Ha ne danke ich habs jetzt geschoben damit der coder übertragbar bleibt tschu
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.