Hallo, ich möchte mir die innere Zahlendarstellung von float und double anschauen. (Mein ATtiny84 kennt kein printf, ich habe nur ein kleines LC-Display) Wie kann ich eine float absichtlich falsch in eine unsigned long Variable casten, um mir das in HEX anzeigen zu lassen?
Du könntest ein memcpy machen und die Bytes mit printf (%x) ausgeben. Grüsse, René
und die dritte Standardmöglichkeit der Vollständigkeit halber: eine union basteln mit einer float und einer uint32_t, dann an die float zuweisen und aus der uint32_t entnehmen.
Standardkonform ist die Verwendung von memcpy. Weder die 2. noch der 3. Vorschlag sind standardkonform, wobei die Verwendung einer Union wie im Vorpost mit GCC funktioniert, aber nicht unbedingt mit anderen (standardkonformen) Compilern.
casten und unions sind beide standardkonform, aber genau wie memcpy sind sie alle undefined behaviour. Das ergibt sich allein schon daraus dass C den Aufbau von floats nicht definiert. Sie sollten aber "zufällig" im GCC funktionieren... Und falls der Compiler das memcpy nicht wegoptimiert kriegt ist das außerdem extrem ineffizient.
Dr. Sommer schrieb: > casten und unions sind beide standardkonform, aber genau wie memcpy sind > sie alle undefined behaviour. Das ergibt sich allein schon daraus dass C > den Aufbau von floats nicht definiert. Der Aufbau von float und der Aufbau von unsigned long. Erst die Kombination der beiden macht es undefiniert. Laut ISO C ist es nämlich durchaus erlaubt, ein beliebiges Objekt, also auch einen float, per memcpy in ein Array aus unsigned char zu kopieren, um auf diese Weise die Byte-Repräsentation zu bekommen. > Und falls der Compiler das memcpy nicht wegoptimiert kriegt ist das > außerdem extrem ineffizient. Dann ist aber auch der Compiler extremer Murks. gcc muß es noch nicht mal wegoptimieren, da es eh komplett im Compiler implementiert ist. Das heißt, daß es selbst bei ganz ausgeschalteten Optimierungen nicht zu einem Funktionsaufruf kommt. Ich habe mal folgende 3 Varianten verglichen:
1 | static inline unsigned long a(float f) |
2 | {
|
3 | return *(unsigned long*)&f; |
4 | }
|
5 | |
6 | static inline unsigned long b(float f) |
7 | {
|
8 | unsigned long ret; |
9 | memcpy(&ret, &f, sizeof ret); |
10 | return ret; |
11 | }
|
12 | |
13 | static inline unsigned long c(float f) |
14 | {
|
15 | union
|
16 | {
|
17 | float f; |
18 | unsigned long u; |
19 | } uf; |
20 | |
21 | uf.f = f; |
22 | return uf.u; |
23 | }
|
Auf avr-gcc mit -O3 kommt bei allen drei exakt das gleiche raus. Bei dem für x86-64 ist die union-Variante eine Instruktion länger. Alles andere ist aber auch da gleich. Was man hier aber schon sieht, ist daß vom Source-Code her die union-Variante irgendwie nach "von hinten durch die Brust in Auge" aussieht.
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.