Forum: Compiler & IDEs int/float => buffer?


von Ray M. (ray_m)


Lesenswert?

hi @all,

aktuell stehe ich vor der problem das ich int_*, uint_*, float usw.
in einen buffer/struct packen muss ...

typedef struct CAN_message_t {
    uint32_t id;      // can identifier
    uint8_t ext;      // identifier is extended
    uint8_t len;      // length of data
    uint16_t timeout; // milliseconds, zero will disable waiting
    uint8_t buf[8];
} CAN_message_t;

static CAN_message_t msg;

in msg.buf muss jetzt ein z.b. ein float rein

gibt es dafür eine standart-lib die man verwenden kann oder schreibt
solche wirklich jeder neu auf diesem platenten, dass würde sich für
mich ziemlich krank anhöhren ???

sowas wie

  int a = 123456;
  convert(msg.buf, a);
  CANbus.write(msg);
  ...
  float b = 1234.56;
  convert(msg.buf, b);
  CANbus.write(msg);

danke für einen eventuellen hinweis oder tip ...

von Peter II (Gast)


Lesenswert?

Ray M. schrieb:
> gibt es dafür eine standart-lib die man verwenden

einfach memcpy

float b = 1234.56;
memcpy(msg.buf, &b);

bei int muss man aber die Byte-order beachten. Das kommt dann auf dein 
System an.

von Ray M. (ray_m)


Lesenswert?

Peter II schrieb:
> Ray M. schrieb:
>> gibt es dafür eine standart-lib die man verwenden
>
> einfach memcpy

so einfach ?

uff ... da hätte ich drauf kommen sollen ... danke

> float b = 1234.56;
> memcpy(msg.buf, &b);

und wie geht es wieder raus ?

int a;
convert(a, msg.buf);

oder

float a = convert(msg.buf);

oder sowas in der art ...

> bei int muss man aber die Byte-order beachten. Das kommt dann auf dein
> System an.


ps: danke fürs beantworten solcher anfängerfragen ;)

von Ray M. (ray_m)


Lesenswert?

Peter II schrieb:
> Ray M. schrieb:
>> gibt es dafür eine standart-lib die man verwenden
>
> einfach memcpy
>
> float b = 1234.56;
> memcpy(msg.buf, &b);

ich hab jetzt

memcpy(msg.buf, &data, sizeof(data));

das scheint zu passen ?

von Peter II (Gast)


Lesenswert?

Ray M. schrieb:
> und wie geht es wieder raus ?

einfach die Parameter von memcpy tauschen
1
//rein
2
memcpy(msg.buf, &b, sizeof(float) );
3
4
//raus
5
memcpy(&b, msg.buf, sizeof(float) );

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ray M. schrieb:
> Peter II schrieb:
>> einfach memcpy
>
> so einfach ?

Wenn die Nachrichten zwischen gleichen Plattformen übertragen werden, 
dann ja.   Ansonsten ist (De-)serialisierung komplizierten, z.B. 
unterschiedlicher Endianess oder sizeof int.

memcpy hat zudem den Vorteil dass es standardkonform ist und i.d.R ohne 
Overhead compiliert wird.

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:
> Wenn die Nachrichten zwischen gleichen Plattformen übertragen werden,
> dann ja.   Ansonsten ist (De-)serialisierung komplizierten, z.B.
> unterschiedlicher Endianess oder sizeof int.

habe ich ja geschrieben, float sollte aber überall passen.

von Ray M. (ray_m)


Lesenswert?

Peter II schrieb:
> Johann L. schrieb:
>> Wenn die Nachrichten zwischen gleichen Plattformen übertragen werden,
>> dann ja.   Ansonsten ist (De-)serialisierung komplizierten, z.B.
>> unterschiedlicher Endianess oder sizeof int.
>
> habe ich ja geschrieben, float sollte aber überall passen.

joop, danke ... da war ich zu schnell ...

es sind alles arm-cortex-m4 am canbus,
da sollten keine probleme mit endianess auftreten

danke nochmal für die super schnelle hilfe ...

von Dirk B. (dirkb2)


Lesenswert?

Mit cast geht es auch
1
float b;
2
3
*(float*)msg.buf = b;
4
5
b = *(float*)msg.buf;

Wenn der Compiler optimiert, sollte kein Unterschied zum memcpy sein.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dirk B. schrieb:
> Mit cast geht es auch

Wozu dieses Type-Punning und Verletzung der Aliasing-Regeln?

von Jim M. (turboj)


Lesenswert?

Dirk B. schrieb:
> Mit cast geht es auch
> float b;
>
> *(float*)msg.buf = b;
>
> b = *(float*)msg.buf;
> Wenn der Compiler optimiert, sollte kein Unterschied zum memcpy sein.

Wenn der Puffer nicht 4-Byte aligned ist, gibt das auf Cortex M4F einen 
Fault, die FPU möchte floats immer nur aligned lesen.

Die memcpy() Version faultet aus eigener Erfahrung normalerweise nicht.

von Falk B. (falk)


Lesenswert?

@Jim Meba (turboj)

>Die memcpy() Version faultet aus eigener Erfahrung normalerweise nicht.

Ich faulte
Du faultest
Er/Sie/Es faultet
Wir faulten
Ihr faultet
Sie faulten

OMG!!!

(Hier ist die Abkürzung im Englischen wie Deutschen zufällig identisch)

http://de.wikipedia.org/wiki/Denglisch

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> Ich faulte
> Du faultest
> [...]

Schon in der Bibel steht:

"...Sie bewahrten es also bis zum Morgen auf, wie es Mose angeordnet 
hatte, und es faulte nicht, noch wurde es madig."

2. Mose 16,24

Scheint bugfrei gewesen zu sein. ;-)

von Ray M. (ray_m)


Lesenswert?

scheiss auf moses, gibt es eigentlich auch so eine elegante
möglichkeit das plattformunabhängig hinzubekommen, thema
endianess, padding usw...

von Jay (Gast)


Lesenswert?

Ray M. schrieb:
> scheiss auf moses, gibt es eigentlich auch so eine elegante
> möglichkeit das plattformunabhängig hinzubekommen, thema
> endianess, padding usw...

Mal locker bleiben, ja?

Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren, 
zur Not selbst gemachten, Funktionen oder geschickt gewählten 
Shift-Operationen.

Float/double packt man ohne genauere Untersuchung gar nicht direkt in 
Messages wenn es plattformunabhängig sein soll. Sondern man untersucht 
erst mal, ob man wirklich ein IEEE 754 Format hat, und ob man nicht von 
Little- nach Big-Endian wandeln muss/soll. htonf() und htond() sind 
selten in Bibliotheken zu finden, also implementiert man sich die 
selber.

Padding vermeidet man, indem man die gesamte Message in einem uint8_t[] 
aufbaut, nicht in irgendwelchen structs, bei denen man dann dem 
jeweiligen Compiler gut zureden muss. Zugegriffen wird auf die einzelnen 
Komponenten einer Message mit Macros oder Funktionen.
1
#define OFFSET_LEN (11)
2
3
#define SET_MSG_LEN(msg, len)  do { msg[OFFSET_LEN] = (uint8_t)(len >> 8); msg[OFFSET_LEN + 1] = (uint8_t)(len & 0xFF) } while(1)

Ja, sieht hässlich aus, ist halt plattformunabhängig.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jay schrieb:
> Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren,

Bei GCC siehe auch __builtin_bswap32()

http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fbswap32-4076

von Franz (Gast)


Lesenswert?

Wer hat denn den Bus spezifiziert?
Ist das ein eigenes (Hobby-) Projekt?

Im Fahrzeug (da wo CAN ursprünglich eingesetzt wurde) sind die Signale 
genormt. Da ist genau spezifiziert welche Endianess welches Signal in 
welcher Botschaft hat.
Dafür kann es aber auch passieren dass dein float nicht byte-aligned 
ist, du also dein memcpy nicht so ohne weiteres benutzen kannst.
CAN überträgt eben 64 Bit, keine 8 Byte...

In einem eigenen Projekt, noch dazu mit nur gleichen Architekturen am 
Bus sollte aber alles passen.

von Markus F. (mfro)


Lesenswert?

Johann L. schrieb:
> Jay schrieb:
>> Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren,
>
> Bei GCC siehe auch __builtin_bswap32()
>
> 
http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fbswap32-4076

Natürlich kann man auf allerhand verschiedene Arten Bytes "rumdrehen", 
wenn man denn weiß, wie rum. Und dazu muß man zuerst mal wissen, auf 
welcher Endianess man gerade rumoperiert.

Der Witz bei htonl() und ntohl() (und ihrer Geschwister) ist aber gerade 
der, daß man es da nicht wissen muß (weil's die Library schon weiß und 
automatisch richtig macht, egal auf welcher Plattform man sitzt).

von Ray M. (ray_m)


Lesenswert?

Markus F. schrieb:
> Johann L. schrieb:
>> Jay schrieb:
>>> Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren,
>>
>> Bei GCC siehe auch __builtin_bswap32()
>>
>>
> 
http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fbswap32-4076
>
> Natürlich kann man auf allerhand verschiedene Arten Bytes "rumdrehen",
> wenn man denn weiß, wie rum. Und dazu muß man zuerst mal wissen, auf
> welcher Endianess man gerade rumoperiert.
>
> Der Witz bei htonl() und ntohl() (und ihrer Geschwister) ist aber gerade
> der, daß man es da nicht wissen muß (weil's die Library schon weiß und
> automatisch richtig macht, egal auf welcher Plattform man sitzt).

dann scheint htonl() usw. die antwort auf die frage zu sein,
danke für den hinweis, ich werde mir das mal ins gehirn tun ...
es kann ja nicht sein das man das rad jedes mal neu erfinden muss

von Konrad S. (maybee)


Lesenswert?

Hier war noch was zum Thema Endianess: 
Beitrag "Re: Erklärung C-Code"

von Markus F. (mfro)


Lesenswert?

Ray M. schrieb:
> dann scheint htonl() usw. die antwort auf die frage zu sein,

Leider auch nicht in jedem Fall.

htonx() und ntohx() sind (logischerweise) auf Big-Endian Systemen No-Ops 
(weil "network byte order" definitionsgemäß schon Big-Endian ist).

Wenn Du dein Übertragungsformat als Little-Endian definierst (was 
ungeschickt wäre) und entsprechend auf einem Big-Endian System eine 
Wandlung nach Little-Endian und zurück brauchst, mußt Du sie erst wieder 
selber schreiben (oder besser: die Macros aus <endian.h> benutzen).

: Bearbeitet durch User
von Ray M. (ray_m)


Lesenswert?

Markus F. schrieb:
> Ray M. schrieb:
>> dann scheint htonl() usw. die antwort auf die frage zu sein,
>
> Leider auch nicht in jedem Fall.
>
> htonx() und ntohx() sind (logischerweise) auf Big-Endian Systemen No-Ops
> (weil "network byte order" definitionsgemäß schon Big-Endian ist).
>
> Wenn Du dein Übertragungsformat als Little-Endian definierst (was
> ungeschickt wäre) und entsprechend auf einem Big-Endian System eine
> Wandlung nach Little-Endian und zurück brauchst, mußt Du sie erst wieder
> selber schreiben (oder besser: die Macros aus <endian.h> benutzen).

na ja, ich frage mich warum es auf so eine zentrale frage so viele
verschiedene antworten gibt ... bei einem problem was seit anbegin
der zeit existiert hätte ich gedacht das es einen standartweg gibt,
in einer c-lib implementiert den man verwenden sollte ...
das scheint nicht der fall zu sein ... für mich ehrlich gesagt
unverständlich ...

von Konrad S. (maybee)


Lesenswert?

Markus F. schrieb:
> Wenn Du dein Übertragungsformat als Little-Endian definierst (was
> ungeschickt wäre) ...

Im Prinzip ist es egal, für welche Endianess man sich bei einem 
eigenen Protokoll entscheidet. Wenn man binäre Daten mit Werten größer 
8 Bit übertragen will, dann muss man sich für eine Endianess 
entscheiden, was oft genug übersehen wird. Es bietet sich an, sich an 
bestehende Konventionen im Umfeld zu halten, z.B. bei TCP/IP gilt 
Network-Byte-Order, also Big-Endian. Da heutzutage TCP/IP überall ist, 
sind auch die ganzen Hilfsfunktionen/-makros für den Umgang mit 
Network-Byte-Order überall verfügbar. Ein Vorteil, den man nutzen kann.

von Ray M. (ray_m)


Lesenswert?

Konrad S. schrieb:
> Markus F. schrieb:
>> Wenn Du dein Übertragungsformat als Little-Endian definierst (was
>> ungeschickt wäre) ...
>
> Im Prinzip ist es egal, für welche Endianess man sich bei einem
> eigenen Protokoll entscheidet. Wenn man binäre Daten mit Werten größer
> 8 Bit übertragen will, dann muss man sich für eine Endianess
> entscheiden, was oft genug übersehen wird. Es bietet sich an, sich an
> bestehende Konventionen im Umfeld zu halten, z.B. bei TCP/IP gilt
> Network-Byte-Order, also Big-Endian. Da heutzutage TCP/IP überall ist,
> sind auch die ganzen Hilfsfunktionen/-makros für den Umgang mit
> Network-Byte-Order überall verfügbar. Ein Vorteil, den man nutzen kann.

ok, dass ist ein argument, also werde ich das so machen, klinkt sinnvoll

danke ...

von Konrad S. (maybee)


Lesenswert?

Ray M. schrieb:
> ok, dass ist ein argument, also werde ich das so machen

Hinterhältigerweise schiebe ich noch ein aber hinterher:
PCs und 'ne Menge Mikrocontroller sind Little-Endian, verstehen sich 
also auch "ohne den ganzen Quatsch".

Wichtig ist, um die Existenz des Problems zu wissen, eine Entscheidung 
zu treffen und zumindest das Ergebnis der Entscheidung im Projekt zu 
dokumentieren.

von Ray M. (ray_m)


Lesenswert?

Konrad S. schrieb:
> Ray M. schrieb:
>> ok, dass ist ein argument, also werde ich das so machen
>
> Hinterhältigerweise schiebe ich noch ein aber hinterher:
> PCs und 'ne Menge Mikrocontroller sind Little-Endian, verstehen sich
> also auch "ohne den ganzen Quatsch".
>
> Wichtig ist, um die Existenz des Problems zu wissen, eine Entscheidung
> zu treffen und zumindest das Ergebnis der Entscheidung im Projekt zu
> dokumentieren.

na ja, dass ist einfach, network-byte-order als standart definiert
und in die docu geschrieben und alles wird gut ;)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ray M. schrieb:
> na ja, dass ist einfach, network-byte-order als standart definiert
> und in die docu geschrieben und alles wird gut ;)

Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke.

von Ray M. (ray_m)


Lesenswert?

Frank M. schrieb:
> Ray M. schrieb:
>> na ja, dass ist einfach, network-byte-order als standart definiert
>> und in die docu geschrieben und alles wird gut ;)
>
> Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke.

jawohl chef ... bitte ;) ;) ;)

von Konrad S. (maybee)


Lesenswert?

Frank M. schrieb:
> Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke.

Ta musd tu turch, auch wänns we dud! ;-)

von Rolf Magnus (Gast)


Lesenswert?

Ray M. schrieb:
> Frank M. schrieb:
>> Ray M. schrieb:
>>> na ja, dass ist einfach, network-byte-order als standart definiert
>>> und in die docu geschrieben und alles wird gut ;)
>>
>> Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke.
>
> jawohl chef ... bitte ;) ;) ;)

Und wenigstens ab und zu mal sinnvolle Verwendung der Shift-Taste 
angewöhnen. Nicht nur C-Compiler, sondern auch Menschen sind 
Case-sensitiv.

Ray M. schrieb:
>> Wichtig ist, um die Existenz des Problems zu wissen, eine Entscheidung
>> zu treffen und zumindest das Ergebnis der Entscheidung im Projekt zu
>> dokumentieren.
>
> na ja, dass ist einfach, network-byte-order als standart definiert
> und in die docu geschrieben und alles wird gut ;)

Meist wird die Entscheidung eher so getroffen, dass eben das genommen 
wird, was die aktuelle Zielplattform benutzt. Das muß auch nicht mal 
unbedingt unsinnig sein. Wenn ich eine Netzwerkverbindung habe, wo immer 
nur zwei PCs 50 MB/s an Daten hin und her schaufeln, brauch ich mir 
nicht unbedingt die Mühe machen, alles erst nach Big Endian und dann 
nachher wieder zurück zu wandeln, nur damit's halt in Network Byte Oder 
ist.

von Jay (Gast)


Lesenswert?

Ray M. schrieb:
> na ja, ich frage mich warum es auf so eine zentrale frage so viele
> verschiedene antworten gibt

Beim Programmieren wird auch heutzutage noch ein bisschen Mitdenken 
erwartet. Es gibt nicht für jede Kleinigkeit gleich eine 3 MB große 
Bibliothek, wenn man etwas mit Bordmitteln in wenigen Zeilen erledigen 
kann. Obwohl ... siehe Unten.

Protokolle implementieren ist sowieso Bitfummelei, da kann man die 
Endianes noch schnell nebenbei erledigen.

> ... bei einem problem was seit anbegin
> der zeit existiert

Für die meisten existiert dieses Problem gar nicht, weil deren Programme 
nicht über die eigene CPU hinauskommen.

Für das größte Netz der Welt ist es gelöst, siehe htonl() und Konsorten. 
Für andere Protokolle steht es in den entsprechenden Standards.

> hätte ich gedacht das es einen standartweg gibt,

Big-Endian für das größte Netz der Welt. Wer will kann es bei 
selbstgebastelten Protokollen diesem Netz gleich tun oder eben nicht.

> in einer c-lib implementiert den man verwenden sollte ...

htonl() und Konsorten für das größte Netz der Welt. Wer will kann die 
auch bei selbstgebastelten Protokollen verwenden oder macht halt was 
anderes.

> das scheint nicht der fall zu sein ... für mich ehrlich gesagt
> unverständlich ...

Bit- und Byte-Order sind Tagesgeschäft wenn man Kommunikationsprotokolle 
programmiert.

Aber, wenn du es dir ganz hart geben möchtest, es gibt so wunderbare 
Systeme wie ASN.1 zu der man noch eine Encoding Rule, z.B. DER, braucht.

Ok, es ist ein bisschen doof, dass es keinen vollständigen ASN.1 
Compiler gibt, und die existierenden Compiler auch schon mal 12 
Durchläufe über den Quelltext brauchen um ein Ergebnis zu produzieren. 
Aber hey, für ein paar 1000 Euro bei kommerziellen Compilern kann man 
schon erwarten, dass der sich ein bisschen anstrengt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> [...] brauch ich mir
> nicht unbedingt die Mühe machen, alles erst nach Big Endian und dann
> nachher wieder zurück zu wandeln, nur damit's halt in Network Byte Oder
> ist.

Sehe ich genauso. Die Network Byte Order befindet sich auf einer anderen 
Ebene als die Anwendungs-Schicht des TCP/IP-Referenzmodells. Es gibt 
überhaupt keine Vorschrift für die Anordnung von Daten im 
Application-Layer.

Am portabelsten wäre wohl die Konvertierung sämtlicher Werte per 
sprintf() in ASCII-Strings, die anschließende Übertragung und 
Zurückkonvertierung per sscanf() auf dem Zielsystem. Effizienz geht aber 
anders...

von Konrad S. (maybee)


Lesenswert?

... und dann kommt wieder "strcmp() funktioniert nicht, kräh-kräh". ;-)
Naja, irgendeinen Tod muss man sterben.

von Rolf Magnus (Gast)


Lesenswert?

Frank M. schrieb:
> Am portabelsten wäre wohl die Konvertierung sämtlicher Werte per
> sprintf() in ASCII-Strings, die anschließende Übertragung und
> Zurückkonvertierung per sscanf() auf dem Zielsystem. Effizienz geht aber
> anders...

Wird aber immer mehr so gemacht, vor allem über's Internet, das ja 
bekannt dafür ist, dass Bandbreite immer in Hülle und Fülle zur 
Verfügung steht. Damit es nicht immer noch zu effizient ist, nimmt man 
aber kein schnödes printf/scanf, sondern XML. Das mit möglichst tiefer 
Verschachtelung und möglichst langen Tag-Namen holt dann das Optimum and 
Overhead raus - sowohl bei der Bandbreite, als auch bei der Rechenzeit. 
Überraschenderweise macht das die Übertragung irgendwie langsam, also 
komprimiert man das ganze noch on the fly, um die Overheads besser 
gegeneinander auszubalancieren. Denn bekanntlich ist ja auch Strom auf 
Geräten wie z.B. Smartphones unbegrenzt verfügbar, und irgendwie muss 
man ja die viele Rechenpower verbraten.

von Jay (Gast)


Lesenswert?

Frank M. schrieb:
> Rolf Magnus schrieb:
>> [...] brauch ich mir
>> nicht unbedingt die Mühe machen, alles erst nach Big Endian und dann
>> nachher wieder zurück zu wandeln, nur damit's halt in Network Byte Oder
>> ist.
>
> Sehe ich genauso. Die Network Byte Order befindet sich auf einer anderen
> Ebene als die Anwendungs-Schicht des TCP/IP-Referenzmodells. Es gibt
> überhaupt keine Vorschrift für die Anordnung von Daten im
> Application-Layer.

Doch, haufenweise, aber gerne für jede Protokollfamilie etwas anders. 
Beispiel: HTML, oder direkt die ganze XML-Familie. Da kommen die 
grundlegenden Vorschriften über das Charset-Encoding rein.

von Le X. (lex_91)


Lesenswert?

Frank M. schrieb:
> Am portabelsten wäre wohl die Konvertierung sämtlicher Werte per
> sprintf() in ASCII-Strings, die anschließende Übertragung und
> Zurückkonvertierung per sscanf() auf dem Zielsystem. Effizienz geht aber
> anders...

Wie immer gibt es kein Schwarz oder Weiß.

Bei einer Anmeldung an einem System (z.B. Server eines eigenen 
Online-Spiels) oder das Senden eines Kommandos alle heilige Zeit finde 
ich ASCII-Daten sehr praktisch. Und halte es auch bei meinem 
Kommandointerpreter selbst auf kleinen Mikrocontrollern so.

Bei Videostreaming oder andere datenintensive Dienste oder wenn eine 
geringe Latenz gefordert ist sollte man vielleicht doch mit Rohdaten 
arbeiten...

von Konrad S. (maybee)


Lesenswert?

Bitte noch verschlüsseln, vorzugsweise vor dem Komprimieren. ;-)

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.