Seite 1 von 1
[C++] Bitweises Interpretieren von Floats
Verfasst: 07.12.2015, 16:14
von Schrompf
Tach auch. Ich muss hier und da
float bitweise bearbeiten. Klingt eigentlich, als wäre es gar kein Problem, ist aber eins. Beispiel:
Code: Alles auswählen
float LiesFloat() {
uint32_t bits = LiesBits(32);
return reinterpret_cast<float&> (bits);
}
Funktioniert. Aber unter Linux warnt der GCC
gcc hat geschrieben:../../Traumklassen/TBitLeser.h
96: warning: dereferencing type-punned pointer will break strict-aliasing rules (-Wstrict-aliasing)
Ich habe mal ein bisschen nach
strict-aliasing gegoogelt und bin der Meinung, dass der GCC da Recht hat. Die Aliasing-Regeln behaupten, dass Zeiger auf verschiedene Datentypen nicht aliasen können, demzufolge bei der Benutzung obigen Codes alle möglichen undefinierten Verhalten auftreten können. Es funktioniert allerdings anscheinend zuverlässig.
Die Frage lautet also: wie greift man verlässlich und warnungsfrei auf die Bits eines
float zu?
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 07.12.2015, 17:23
von Krishty
Erstmal: Unter Visual C++ (und Clang im Kompatibilitätsmodus) geht das, weil Win32 Aliasing erlaubt. Der Workaround gilt also nur für GCC.
AFAIR sollte GCC
union gefallen:
Code: Alles auswählen
union FloatAndInt {
float f;
uint32_t i;
} fi;
fi.i = LiesBits(32);
return fi.f;
Standardkonform ist das nicht (standardkonform ist nichts außer
memcpy()), aber wie gesagt der bevorzugte Weg für GCC.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 07.12.2015, 21:29
von Spiele Programmierer
Ich habs drüben auf SPPRO ja schon geschrieben.
Im Graugebiert ist das nur in C++, in C ist es aber voll erlaubt.
(
http://stackoverflow.com/questions/1137 ... d-behavior)
GCC kennt noch eine weitere Möglichkeit:
may_alias
Ich persönlich würde auch die union-Variante verwenden, außer es gibt exotische Gründe die etwas anderes erfordern.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 07.12.2015, 21:53
von Schrompf
Jau, auch hier nochmal Danke. Es wird dann wohl die union werden, auch wenn ich die wohl nicht mit irgendwelchen Bequemlichkeits-Methoden ausstatten werde. Speziell der VisualStudio-Compiler ist sehr empfindlich, was sowas angeht, und ich rechne bei diesem Konstrukt mit einigen hundert Millionen Aufrufen. Da werde ich eh irgendwann mal die ASM-Ergebnisse durchgucken müssen.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 07.12.2015, 22:28
von Krishty
Wenn es so viele sind, vielleicht lieber SSE? Da gibt es dann innerhalb von wenigen Takten in den Registern statt über den Speicher wie in der skalaren Variante … _mm_castsi128_ps dürfte das Zauberintrinsic sein.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 07.12.2015, 23:54
von Schrompf
Jau, SSE steht dann auch noch aus.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 01:08
von FlorianB82
Moin Schrompf,
ich habe mich mit solchen Themen auch schon zur Genüge auseinandergesetzt - schon alleine, weil ich beruflich zwischen Hardware und Software herumgeistere. Jetzt nur schnell aus dem Gedächtnis - ohne Anspruch auf Topgenauigkeit:
Die meisten aktuellen C++-Compiler führen keine Optimierungen aufgrund der Strict-Aliasing-Rules durch - da sollte also trotz der Warnung kein unerwartetes Verhalten aufgrund Optimierung auftreten. Soweit ich aber weiß, führen neuere GCC-Versionen solche Optimierungen durch - hier könntest du dann gegebenenfalls interessante Effekte beobachten.
Wenn du die Warnung vernünftig losbekommen willst - was ich nur begrüßen kann, da ich ein großer Freund von Warning-Free-Code bin - gibt es immer die Möglichkeit, über einen char-Pointer (signed oder unsigned) zu casten. Gemäß der Strict-Aliasing-Rules dürfen (unsigned/signed) char*-Pointer nämlich jeden beliebigen Typ aliasen, und du bist damit safe und standardkonform.
Über einen Union zu gehen ist eigentlich auch Murks. Interessant, dass der Compiler da nicht meckert. Wenn mich nicht alles täuscht, erlaubt der C++-Standard nur das Lesen aus einem Feld eines Unions, in das man vorher auch geschrieben hat - alles andere ist UB. Da du das aber genau machen würdest (in i schreiben und aus f lesen), kannste dir das auch sparen. Ist auch nicht besser oder schlechter als der brutalo-cast.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 06:07
von dot
FlorianB82 hat geschrieben:Die meisten aktuellen C++-Compiler führen keine Optimierungen aufgrund der Strict-Aliasing-Rules durch - da sollte also trotz der Warnung kein unerwartetes Verhalten aufgrund Optimierung auftreten. Soweit ich aber weiß, führen neuere GCC-Versionen solche Optimierungen durch - hier könntest du dann gegebenenfalls interessante Effekte beobachten.
Da irrst du dich gewaltig! Die Strict-Aliasing-Rule ist Grundnahrungsmittel jedes auch nur annähernd brauchbaren Compilers und für die Performance von C++ von essentieller Bedeutung. Ohne die müsste der Compiler davon ausgehen, dass jede Modifikation eines Objektes potentiell den Wert jedes anderen Objektes verändert, was bedeuten würde, dass der Compiler nach jeder Modifikation irgendeines Objektes die Werte aller anderen Objekte neu aus dem Speicher laden muss, bevor er sie wieder verwenden kann. Oft ist selbst die Strict-Aliasing-Rule nicht genug, genau darum bietet so ziemlich jeder Compiler eine Variante des
restrict Keywords als Extension an...
Nur mal so als kleine Illustration:
Code: Alles auswählen
int blub(int* i, float* f)
{
*i = 10;
*f = 32.0f;
return *i + *f;
}
int main()
{
union
{
float f;
int i;
} x;
return blub(&x.i, &x.f);
}
Jeder gängige Compiler wird dir das – dank Strict-Aliasing-Rule – zu einem
return 42; optimieren. Ändern wir den
int zu
char, sieht die Sache plötzlich völlig anders aus...
FlorianB82 hat geschrieben:Wenn du die Warnung vernünftig losbekommen willst - was ich nur begrüßen kann, da ich ein großer Freund von Warning-Free-Code bin - gibt es immer die Möglichkeit, über einen char-Pointer (signed oder unsigned) zu casten. Gemäß der Strict-Aliasing-Rules dürfen (unsigned/signed) char*-Pointer nämlich jeden beliebigen Typ aliasen, und du bist damit safe und standardkonform.
Die Frage ist nur, was du mit diesem
char* dann tun willst (
signed char wäre übrigens bereits ab hier schon wieder UB, nur
char und
unsigned char dürfen aliasen). Willst du auf irgendein anderes als das erste Byte der Objektrepräsentation, auf die dein
char* zeigt, zugreifen, wirst du Pointerarithmetik betreiben müssen und spätestens dann haben wir UB, denn Pointerarithmetik auf Pointern, die nicht in ein Array oder auf das letzte Element eines Arrays zeigen, ist UB... ;)
FlorianB82 hat geschrieben:Über einen Union zu gehen ist eigentlich auch Murks. Interessant, dass der Compiler da nicht meckert. Wenn mich nicht alles täuscht, erlaubt der C++-Standard nur das Lesen aus einem Feld eines Unions, in das man vorher auch geschrieben hat - alles andere ist UB. Da du das aber genau machen würdest (in i schreiben und aus f lesen), kannste dir das auch sparen. Ist auch nicht besser oder schlechter als der brutalo-cast.
In der Tat; das funktioniert leider alles nicht...
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 08:44
von Schrompf
Hm. Klingt für mich, als wäre ich im UB, egal was ich tue. Ich habe hier aktuell die union-Lösung implementiert, die zumindest auf dem GCC warnungsfrei kompiliert und das tut, was sie soll. Ein Hoch auf Unittests. Ob und wie sich Visual Studio damit schlägt, werde ich jetzt aber so schnell nicht herausfinden. Und den entstehenden ASM-Code werde ich mir am Ende eh zu Gemüte führen müssen, da das Manöver u.A. Teil meines Voxelkrams ist, der potentiell Gigabytes davon durchackert.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 09:52
von Krishty
dot hat geschrieben:Die Strict-Aliasing-Rule ist Grundnahrungsmittel jedes auch nur annähernd brauchbaren Compilers und für die Performance von C++ von essentieller Bedeutung.
Die Strict Aliasing Rule ist
nur für GCC von essentieller Bedeutung. Und sie ist grundsätzlich falsch (weil C++ das Re-Instanzieren einer Variable am alten Platz mit neuem Typ erlaubt) und die GCC-Leute haben, als sie das gemerkt haben, einfach beschlossen, sie doch drin zu lassen weil sie in 99 % der Fälle halt funktioniert (indem sie den User sinnlos nervt). Ich sehe das als bloße Schikane.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 12:54
von Krishty
Noch kurz an Schrompf:
- Kapsle das in einer Funktion – bloß nicht an jeder Stelle, an der du ein float liest, diesen union-Kack und die enstprechenden #if __GCC__ reproduzieren (machst du sowieso nicht, aber hier lesen ja noch andere mit)
- Diese Funktion sollte auf keinen Fall Referenz oder Zeiger zurückgeben, sondern unbedingt eine neue Instanz – sonst produzieren viele Compiler tatsächlich jede Menge nutzlose Loads und Stores, sobald du mit dem Wert arbeitest
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 13:07
von dot
Krishty hat geschrieben:dot hat geschrieben:Die Strict-Aliasing-Rule ist Grundnahrungsmittel jedes auch nur annähernd brauchbaren Compilers und für die Performance von C++ von essentieller Bedeutung.
Die Strict Aliasing Rule ist
nur für GCC von essentieller Bedeutung. Und sie ist grundsätzlich falsch (weil C++ das Re-Instanzieren einer Variable am alten Platz mit neuem Typ erlaubt) und die GCC-Leute haben, als sie das gemerkt haben, einfach beschlossen, sie doch drin zu lassen weil sie in 99 % der Fälle halt funktioniert (indem sie den User sinnlos nervt). Ich sehe das als bloße Schikane.
Ok, offenbar verstehen wir unter der Strict-Aliasing-Rule was anderes!? Ich verstehe drunter die Regel, die besagt, dass es UB ist, auf das stored value eines Objektes über etwas anderes als ein dem
dynamischen Typ des Objektes entsprechendes glvalue oder ein glvalue vom Typ
char oder
unsigned char zuzugreifen (die restlichen Ausnahmen seien hier mal egal). Diese Regel ist definitiv nicht "falsch" und von MSVC über clang bis zu nvcc macht
jeder Compiler, mit dem ich je zu tun hatte, ständig davon Gebrauch...
Schrompf hat geschrieben:Hm. Klingt für mich, als wäre ich im UB, egal was ich tue. Ich habe hier aktuell die union-Lösung implementiert, die zumindest auf dem GCC warnungsfrei kompiliert und das tut, was sie soll. Ein Hoch auf Unittests. Ob und wie sich Visual Studio damit schlägt, werde ich jetzt aber so schnell nicht herausfinden. Und den entstehenden ASM-Code werde ich mir am Ende eh zu Gemüte führen müssen, da das Manöver u.A. Teil meines Voxelkrams ist, der potentiell Gigabytes davon durchackert.
Wie gesagt:
memcpy() in ein char Array ist die einzige, mir bekannte Vorgehensweise, die vermutlich eher kein UB als UB ist. In der Praxis wird der Type-Punning-per-union-Hack funktionieren, weil praktisch jeder Compiler ihn supported. Es ist aber natürlich dennoch UB...
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 13:21
von Krishty
dot hat geschrieben:Krishty hat geschrieben:dot hat geschrieben:Die Strict-Aliasing-Rule ist Grundnahrungsmittel jedes auch nur annähernd brauchbaren Compilers und für die Performance von C++ von essentieller Bedeutung.
Die Strict Aliasing Rule ist
nur für GCC von essentieller Bedeutung. Und sie ist grundsätzlich falsch (weil C++ das Re-Instanzieren einer Variable am alten Platz mit neuem Typ erlaubt) und die GCC-Leute haben, als sie das gemerkt haben, einfach beschlossen, sie doch drin zu lassen weil sie in 99 % der Fälle halt funktioniert (indem sie den User sinnlos nervt). Ich sehe das als bloße Schikane.
Ok, offenbar verstehen wir unter der Strict-Aliasing-Rule was anderes!? Ich verstehe drunter die Regel, die besagt, dass es UB ist, auf das stored value eines Objektes über etwas anderes als ein dem
dynamischen Typ des Objektes entsprechendes glvalue oder ein glvalue vom Typ
char oder
unsigned char zuzugreifen (die restlichen Ausnahmen seien hier mal egal).
Stimmt; ich habe sie glatt mit Type-Based Aliasing Analysis verwechselt :( Sorry! Der Compiler macht von der Strict Aliasing Rule aber fast keinen Gebrauch, sondern nur von der eventuell abgeleiteten Type-Based Aliasing Analysis (und
die ist im Arsch, weil Dynamic Types ein Analyse-Horror sind). MSVC sowieso nicht, weil die Win32-Garantien dort Vorrang gegenüber C++-Regeln haben (und da darf man eben casten, so viel man will).
dot hat geschrieben:Wie gesagt: memcpy() in ein char Array ist die einzige, mir bekannte Vorgehensweise, die vermutlich eher kein UB als UB ist.
Richtig. Seit ein paar Jahren könnten Compiler auch clever genug sein, das zu optimalem Code zu optimieren (
cbloom hat da was erwähnt –
11-14-15 | Copying words). Wenn du's ausprobierst, poste bitte mal das Disassembly mit VC 2015 und GCC.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 13:51
von dot
Krishty hat geschrieben:dot hat geschrieben:Wie gesagt: memcpy() in ein char Array ist die einzige, mir bekannte Vorgehensweise, die vermutlich eher kein UB als UB ist.
Richtig. Seit ein paar Jahren könnten Compiler auch clever genug sein, das zu optimalem Code zu optimieren (
cbloom hat da was erwähnt –
11-14-15 | Copying words). Wenn du's ausprobierst, poste bitte mal das Disassembly mit VC 2015 und GCC.
Wie
hier schon erwähnt, kompilieren gcc, clang, MSVC und icc ein solches
memcpy() zu einem einfachen move... :)
Beispiel zum
selbst ausprobieren:
Code: Alles auswählen
#include <new>
#include <cstring>
unsigned int float_as_int(float f)
{
unsigned char b[4];
//unsigned int x;
std::memcpy(&b, &f, sizeof(b));
//std::memcpy(&x, &f, sizeof(x));
//new (b) float(f);
return (b[0] << 0) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
//return x;
}
int main()
{
return float_as_int(42.0f);
}
Leider ist MSVC nicht schlau genug um das bitweise Zusammenbauen zu einem int zu erkennen. gcc und clang machen wirklich nur ein move aus der ganzen Funktion...
@Schrompf: Da oben findest du auch noch eine bisher nicht erwähnte, alternative Variante zu Type-punning über placement new. Ist leider aber auch UB... ;)
Edit: Ok, wenn man es so schreibt:
Code: Alles auswählen
((b[0] << 0) & 0xFF) | ((b[1] << 8) & 0xFF) | ((b[2] << 16) & 0xFF) | ((b[3] << 24) & 0xFF)
dann macht auch MSVC nur ein move aus dem ganzen Ding... :)
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 14:31
von Krishty
Danke, der Thread war noch nicht verlinkt.
Krishty hat geschrieben:Der Beispielcode ist für den umgekehrten Fall, float zu int. Wie würde int zu float aussehen? Danach können wir zu den einzelnen Anweisungen kommen :)
Okay; so wie ich das sehe erzeugen Clang und GCC für alle Möglichkeiten (Placement
new,
union,
memcpy,
reinterpret_cast) den gleichen Code. Sehr schön.
Ich setze mal SSE2 voraus weil ich weiß, dass Schrompf das benutzt:
-O3 -msse2
Da wäre das erstrebenswerte Ergebnis ein einzelnes MOVD der Ganzzahl in ein SSE-Register (Register zu Register, ohne Memory Roundtrip). Clang bekommt das hin:
int_as_float(unsigned int):
movd xmm0, edi
ret
GCC nicht:
int_as_float(unsigned int):
mov DWORD PTR [rsp-4], edi
movss xmm0, DWORD PTR [rsp-4]
ret
Visual C++? Keine Ahnung. Als ich das letzte Mal versuchte habe, MOVD aus dem herauszukitzeln, hatte ich einen Blackout und jemand muss währenddessen mit Fäkalien SSE-Intrinsics auf meine Wände geschmiert haben.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 14:56
von dot
Code: Alles auswählen
#include <cstdint>
#include <limits>
#include <cstring>
std::uint32_t float_as_int(float f)
{
static_assert(sizeof(float) == 4);
static_assert(std::numeric_limits<float>::is_iec559);
unsigned char b[4];
std::memcpy(&b, &f, sizeof(b));
return ((b[0] << 0U) & 0xFFU) |
((b[1] << 8U) & 0xFF00U) |
((b[2] << 16U) & 0xFF0000U) |
((b[3] << 24U) & 0xFF000000U);
}
float int_as_float(std::uint32_t i)
{
static_assert(sizeof(float) == 4);
static_assert(std::numeric_limits<float>::is_iec559);
unsigned char b[4] = {
static_cast<unsigned char>((i & 0xFFU) >> 0),
static_cast<unsigned char>((i & 0xFF00U) >> 8),
static_cast<unsigned char>((i & 0xFF0000U) >> 16),
static_cast<unsigned char>((i & 0xFF000000U) >> 24)
};
float f;
std::memcpy(&f, b, sizeof(b));
return f;
}
int main()
{
return int_as_float(float_as_int(42.0f));
}
MSVC bekommt es leider gar nicht hin (vergesst den Edit von vorhin, der Code war falsch), icc auch nicht, gcc nur für eine der beiden Funktionen. clang generiert für
alles perfekten Code:
Code: Alles auswählen
float_as_int(float):
movd eax, xmm0
ret
int_as_float(unsigned int):
movd xmm0, edi
ret
main:
mov eax, 42
ret
I'm seriously impressed :o
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 14:59
von xq
Wow, das ist mal wirklich gute Optimierung! Schöne Sache :)
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 15:42
von Schrompf
Sorry, den sppro-Thread hätte ich auch selbst verlinken sollen. Da kam auch einiges Gutes bei rum. Ich freue mich auch hier sehr, so viel Input zu diesem nur scheinbar simplen Problem zu bekommen. Nach Allem bin ich jetzt aber *noch* verwirrter, wie ich das Problem nun eigentlich lösen soll. Mir wird wohl nichts anderes übrigbleiben, als mal alle Möglichkeiten aufzustellen und durch alle drei bei mir benutzten Compiler zu scheuchen: VC, GCC, CLANG. ICC ist ein interessanter Gedanke, aber für mich aktuell nicht relevant.
Ich werde für den Voxel-Kram sogar bis SSE4 hoch voraussetzen, weil irgendwo da erst irgendwelche Bit-Operationen dazukommen, mit denen ich einige Voxelklumpen-Operationen schneller hinbekomme.
[Edit] Der Vollständigkeit wegen: der Thread drüben im sppro findet sich unter
https://www.spieleprogrammierer.de/18-c ... on-floats/
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 16:04
von dot
Folgende Version ist (sagen wir mal) Endian-independent, imo
einigermaßen standardkonform und erzeugt unter MSVC, clang und gcc den besten Code, den ich dem jeweiligen Compiler bisher entlocken konnte (icc schneidet interessanterweise am schlechtesten ab, wobei Version 13 wohl nicht die neueste ist):
Code: Alles auswählen
#include <cstdint>
#include <limits>
#include <cstring>
std::uint32_t float_as_int(float f)
{
static_assert(sizeof(float) == sizeof(std::uint32_t), "float not 32 bits wide");
static_assert(std::numeric_limits<float>::is_iec559, "float not IEEE 754 compliant");
std::uint32_t i;
std::memcpy(&i, &f, sizeof(std::uint32_t));
return i;
}
float int_as_float(std::uint32_t i)
{
static_assert(sizeof(float) == sizeof(std::uint32_t), "float not 32 bits wide");
static_assert(std::numeric_limits<float>::is_iec559, "float not IEEE 754 compliant");
float f;
std::memcpy(&f, &i, sizeof(std::uint32_t));
return f;
}
int main()
{
return int_as_float(float_as_int(42.0f));
}
Bin immer noch extrem impressed vom Code, den clang generiert... :o
Man sollte erwähnen, dass der union-Hack unter allen Compilern den selben Code erzeugt (icc kommt mit union besser zurecht)...
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 16:08
von Schrompf
Cool, Danke für Deine Zeit! Ich will das zwar alles mal durchprobieren, aber ich komme dazu frühestens im neuen Jahr. Und dann stehen die Chancen gut, dass ich mich gar nicht mehr daran erinnere :-)
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 16:11
von dot
Ich kann zum schnellen Rumprobieren nur nochmal meine Empfehlung wiederholen:
http://gcc.godbolt.org/ ;)
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 16:25
von Alexander Kornrumpf
dot hat geschrieben:imo einigermaßen standardkonform
Nur mal so aus Neugier, es muss doch einen bekannten standardkonformen, schlimmstenfalls langsamen Weg geben, an die Bits von beliebigem zu kommen. Im Zweifelsfall über einen Stream?!
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 16:32
von dot
Alexander Kornrumpf hat geschrieben:dot hat geschrieben:imo einigermaßen standardkonform
Nur mal so aus Neugier, es muss doch einen bekannten standardkonformen, schlimmstenfalls langsamen Weg geben, an die Bits von beliebigem zu kommen. Im Zweifelsfall über einen Stream?!
Kopieren per
std::memcpy() in ein char Array ist der einzige, mir bekannte, arguably wirklich standardkonforme Weg (und der funktioniert nur, so lange es sich um einen trivially-copyable Type handelt).
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 16:59
von Biolunar
dot hat geschrieben:Alexander Kornrumpf hat geschrieben:dot hat geschrieben:imo einigermaßen standardkonform
Nur mal so aus Neugier, es muss doch einen bekannten standardkonformen, schlimmstenfalls langsamen Weg geben, an die Bits von beliebigem zu kommen. Im Zweifelsfall über einen Stream?!
Kopieren per
std::memcpy() in ein char Array ist der einzige, mir bekannte, arguably wirklich standardkonforme Weg (und der funktioniert nur, so lange es sich um einen trivially-copyable Type handelt).
In C99 und C11 ist das Konvertieren per
union ebenfalls standardkonform (in C89 nicht!). Im Standard steht auch was von Zugriff über einen „character type“, ich nehme daher an, dass der Zugriff über
char,
signed char und
unsigned char Pointer wohldefiniert ist.
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 17:08
von Krishty
Mach noch ein static_assert() mit alignof!
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 17:17
von dot
Biolunar hat geschrieben:dot hat geschrieben:Alexander Kornrumpf hat geschrieben:dot hat geschrieben:imo einigermaßen standardkonform
Nur mal so aus Neugier, es muss doch einen bekannten standardkonformen, schlimmstenfalls langsamen Weg geben, an die Bits von beliebigem zu kommen. Im Zweifelsfall über einen Stream?!
Kopieren per
std::memcpy() in ein char Array ist der einzige, mir bekannte, arguably wirklich standardkonforme Weg (und der funktioniert nur, so lange es sich um einen trivially-copyable Type handelt).
In C99 und C11 ist das Konvertieren per
union ebenfalls standardkonform (in C89 nicht!). Im Standard steht auch was von Zugriff über einen „character type“, ich nehme daher an, dass der Zugriff über
char,
signed char und
unsigned char Pointer wohldefiniert ist.
Ja, in C11 ist der Zugriff über char Pointer wohldefiniert (offenbar sogar für
signed char). In C++ ist das dagegen alles UB.
Krishty hat geschrieben:Mach noch ein static_assert() mit alignof!
Sollte imo nicht nötig sein, da wir ja kopieren... ;)
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 17:22
von Krishty
dot hat geschrieben:Krishty hat geschrieben:Mach noch ein static_assert() mit alignof!
Sollte imo nicht nötig sein, da wir ja kopieren... ;)
Ach stimmt; klar :)
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 17:27
von Schrompf
Moment mal. Soll das bedeuten, dass ein Umweg über char* ok ist:
Code: Alles auswählen
float f = *(reinterpret_cast<const float*> (reinterpret_cast<const char*> (&i)));
Aber mein ursprünglicher Weg ohne die Zwischenstufe nicht?
Ernsthaft?
Re: [C++] Bitweises Interpretieren von Floats
Verfasst: 09.12.2015, 17:30
von dot
Nein, ist beides gleichermaßen UB, auch in C.
Abgesehen davon, sollte man wohl erwähnen, dass Type-Punning per union in C11 an sich zwar kein UB sein mag, der C11 Standard aber auch nicht sagt, dass das Ganze dann nicht crashen darf, wenn der uminterpretierte Bitpattern dummerweise gerade kein gültiger Wert des jeweiligen Typs ist (die entsprechende Fußnote weist sogar explizit darauf hin), was die Nützlichkeit des Ganzen dann doch wieder stark relativiert...