In seinem kürzlich gehaltenen Vortrag "Type punning in modernem C ++" sagte Timur Doumler , dass std::bit_cast
dies nicht zum Bit-Casting float
in ein verwendet werden kann, unsigned char[4]
da Arrays im C-Stil nicht von einer Funktion zurückgegeben werden können. Wir sollten entweder std::memcpy
C ++ 23 (oder später) verwenden oder warten, bis etwas wie reinterpret_cast<unsigned char*>(&f)[i]
gut definiert wird.
Können wir in C ++ 20 ein std::array
mit verwenden std::bit_cast
,
float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
anstelle eines C-artigen Arrays, um Bytes eines float
?
quelle
struct X { unsigned char elems[5]; };
der von Ihnen angegebenen Regel entspricht. Es kann sicherlich mit bis zu 4 Elementen listinitialisiert werden. Es kann auch mit 5 Elementen listeninitialisiert werden. Ich glaube nicht, dass ein Standard-Bibliotheksimplementierer die Leute genug hasst, um dies tatsächlich zu tun, aber ich denke, es ist technisch konform.elems[5]
. Und an diesem Punkt kann ich nicht sehen, wie Sie mit einem Aggregat enden könnten, wosizeof(array<char, sizeof(T)>) != sizeof(T)
?struct X { unsigned char c1, c2, c3, c4; };
oderstruct X { unsigned char elems[4]; };
- zuzulassen , während die Zeichen die Elemente dieses Aggregats sein müssen, können sie entweder direkte Aggregatelemente sein oder Elemente eines einzelnen Unteraggregats.P -> Q
nichts über den Fall impliziert, in dem!P
array
selbst keine Auffüllung hat. Implementierungen davon haben möglicherweise keine Auffüllung (und alle Implementierungen, die dies tun, sollten als dysfunktional angesehen werden), aber es gibt keine Garantie dafür, dass dies nicht der Fall istarray
.Die akzeptierte Antwort ist falsch, da Ausrichtungs- und Auffüllprobleme nicht berücksichtigt werden.
Per [Array] / 1-3 :
Der Standard verlangt eigentlich nicht
std::array
genau ein öffentliches Datenelement vom TypT[N]
, daher ist es theoretisch möglich, dasssizeof(To) != sizeof(From)
oderis_trivially_copyable_v<To>
.Ich werde überrascht sein, wenn dies in der Praxis nicht funktioniert.
quelle
Ja.
Nach dem Papier , das das Verhalten von
std::bit_cast
und seine vorgeschlagene Implementierung beschreibt , sofern beide Typen dieselbe Größe haben und trivial kopierbar sind, sollte die Besetzung erfolgreich sein.Eine vereinfachte Implementierung von
std::bit_cast
sollte ungefähr so aussehen:Da ein float (4 Bytes) und ein Array von
unsigned char
withsize_of(float)
Bezug auf alle diese Asserts den Basiswertstd::memcpy
wird durchgeführt. Daher ist jedes Element in dem resultierenden Array ein aufeinanderfolgendes Byte des Floats.Um dieses Verhalten zu beweisen, habe ich im Compiler Explorer ein kleines Beispiel geschrieben, das Sie hier ausprobieren können: https://godbolt.org/z/4G21zS . Der float 5.0 wird ordnungsgemäß als Array von bytes (
Ox40a00000
) gespeichert , das der hexadezimalen Darstellung dieser float-Zahl in Big Endian entspricht .quelle
std::array
garantiert keine Füllbits usw. vorhanden sind?auto bits = reinterpret_cast<std::array<unsigned char, sizeof(float)>&>(f)
und genau die gleiche Ausgabe erhalten. Beweist es etwas?std::array
die Anforderungen von ContiguiosContainer (seit C ++ 17) .std::vector
erfüllt auch die gleichen Kriterien und kann hier offensichtlich nicht verwendet werden. Gibt es etwas, dasstd::array
die Elemente in der Klasse (in einem Feld) enthalten muss, um zu verhindern, dass sie ein einfacher Zeiger auf das innere Array sind? (wie in Vektor, der auch eine Größe hat, die Array nicht in einem Feld haben muss)std::array
erfordert effektiv, dass die Elemente darin gespeichert werden, aber ich mache mir Sorgen über Layoutprobleme.