Hallo, von einem Gerät (Analyser) das per serieller Schnittstelle angesprochen wird, möchte ich die Datenpaketgröße abfragen. Problem ist: die ist bis zu 3 Bytes groß. Der Ablauf ist wie folgt: ich versende ein Kommando, und der Analyser liefert die Datenpaketgröße für folgende Abfragen zurück. Meine übergeordneten Funktionen müssen sich dann dementsprechend verhalten. Nun ist miene Frage: wie erzeuge ich aus 3 einzelnen Bytes/Chars ein unsigned long/eine Zahl? unsigned long receive_size(void) { // "Kommando" zur Bestimmung der Paketgröße unsigned char size[3] = {0x0D, 0x01, 0xA2}; // Kommando absenden receive_cmd (&size[0]); // Paketgröße zurückliefern return size[0] * 256 + size[1] *16 + size[2]; // <-- wie gibt man ein long zurück, bzw, wie setzt man das zusammen? } Gruß, Peter
Peter Maier wrote: > return size[0] * 256 + size[1] *16 + size[2]; // <-- wie gibt man ein > long zurück, bzw, wie setzt man das zusammen? Der Ansatz ist doch nicht schlecht. Nur dass in einem Byte bis 256 gezählt werden kann und nicht nur bis 16 Du musst nur aufpassen, dass die Zwischenergebnisse keinen Overflow produzieren. 256 ist eine int Zahl und dementsprechend wird die Multiplikation in int gemacht. Genau das willst du nicht. Du willst das die Berechnung bereits in unsigned long gemacht wird um Overflows zu vermeiden. return size[0] * 65536UL + size[1] * 256UL + size[2];
Naja, schon fast richtig. Wenn man also annimmt, dass das erste zurückgelieferte Byte auch das höchstwertige ist, dann würde das so aussehen:
1 | unsigned long length; |
2 | |
3 | // dein code...
|
4 | |
5 | length = ((unsigned long)size[0] << 16) + ((unsigned long)size[1] << 8) + size[2]; |
6 | |
7 | return length; |
Dein Ansatz war also schon ganz ok. Multiplizieren mit 256 ist das selbe wie 8x links schieben. Die Multiplikation mit 16 war jedoch verkehrt (4bit links geschoben). Ein long sieht je nun so aus: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx (32bit) Jetzt kommst du mit deinen Einzelbytes: xxxxxxxx yyyyyyyy zzzzzzzz Nun mußt du nur noch schieben und verodern oder addieren und fertig: xxxxxxxx << 16 yyyyyyyy << 8 zzzzzzzz bleibt so
so zum Beispiel:
1 | long l; |
2 | ((char*)(&l))[0]=size[0]; |
3 | ((char*)(&l))[1]=size[1]; |
4 | ((char*)(&l))[2]=size[2]; |
5 | return l; |
oder so:
1 | return ((long)(size[0])<<16)+((long)(size[1])<<8)+((long)(size[2])<<0); |
MfG Mark
Mist schon wieder zu langsam, Karl-Heinz...
Mark Prediger wrote: > so zum Beispiel: >
1 | > long l; |
2 | > ((char*)(&l))[0]=size[0]; |
3 | > ((char*)(&l))[1]=size[1]; |
4 | > ((char*)(&l))[2]=size[2]; |
5 | > return l; |
6 | >
|
>
Wenn schon trickreich, dann richtig trickreich :-)
1 | unsigned long receive_size(void) |
2 | {
|
3 | // "Kommando" zur Bestimmung der Paketgröße
|
4 | unsigned char size[4] = {0x00, 0x0D, 0x01, 0xA2}; |
5 | // Kommando absenden
|
6 | receive_cmd (&size[1]); |
7 | // Paketgröße zurückliefern
|
8 | return *(unsigned long*)size; |
9 | }
|
Hi, erst mal vielen Dank. Das ging ja schneller als erhofft. Echt super eure Hilfe. Die ersten Postings verstehe ich (und wäre da evtl. auch noch irgendwann drauf gekommen das ein Byte bis 256 geht und ein Nibble bis 16), die letzten drei (ok, das mittlere davon schon ;=)) jedoch nicht mehr :=( Zum "ersten Missverständins": es wird ein unsigned long lokal definiert, und dann per Char Zeigeroperation auf die einzelnen Bytes des long zugegriffen. Warum fange ich mit dem Index des long nicht bei [1] an und gehe bis [3]. Das erste Byte (alos [0]) ist ja das MSB, das soll ja auf 0x00 bleiben. Bekomme ja nur drei Bytes zurück. Zum "letzten Missverständnis": ich definiere ein 4 Byte char Array (= 1 long), übergebe der Funktion nur die letzten 3 Bytes, liefer dann aber ab dem ersten Byte zurück. Tricky ;=) Wäre ich nie drauf gekommen. Wobei ich mir da das mit den * Operatoren noch mal durch den Kopf gehen lassen muss. Gibt jetzt nur ein kleines Problem: size [2] ist das LSB, size[0] das MSB Insofern funktionieren die Tricks nicht mehr. Trotzdem, werde ich im Hinterkopf behalten. Danke, Peter
Peter Maier wrote: > ab dem ersten Byte zurück. Tricky ;=) Wäre ich nie drauf gekommen. Wobei > ich mir da das mit den * Operatoren noch mal durch den Kopf gehen lassen Mach dir um die Multiplikationen keine Sorgen. Da die Konstanten 2-er Potenzen sind wir das jeder optimierende Compiler, der etwas auf sich hält in Schiebeoperationen umwandeln. > Gibt jetzt nur ein kleines Problem: size [2] ist das LSB, size[0] das > MSB Insofern funktionieren die Tricks nicht mehr. Liese sich ev. durch eine andere Beschreibereihenfolge in der read Funktion beheben. Allerdings: Das ist ein Trick aus der untersten Schublade und weit davon entfernt auf jedem C System zu funktionieren (genau aus den Gründen, die die angeführt hast).
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.