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
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
unsignedcharArray[4];
2
3
Array[0]=erster_Wert_den_dubekommst;
4
Array[1]=zweiter_Wert_den_du_bekommst;
5
Array[2]=dritter_Wert_den_du_bekommst;
6
Array[3]=vierter_Wert_den_du_bekommst;
7
8
longvalue=*(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.
> 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.
> 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.
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 ...
>> 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
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
unsignedlongvalue=
2
(unsignedlong)byte[0]<<24|
3
(unsignedlong)byte[1]<<16|
4
(unsignedint)byte[2]<<8|
5
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.
Die union Lösung ist genauso gut oder schlecht, wie
1
longvalue=*(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
MNR wrote:
> Die union Lösung ist genauso gut oder schlecht, wie
1
longvalue=
2
>*(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).
> 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:
@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äß