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.