W swoim ostatnim przemówieniu „Pisanie czcionek we współczesnym C ++” Timur Doumler powiedział, że std::bit_cast
nie można go użyć do wrzucenia a float
do, unsigned char[4]
ponieważ tablice w stylu C nie mogą zostać zwrócone z funkcji. Powinniśmy albo użyć, std::memcpy
albo poczekać, aż C ++ 23 (lub nowszy), kiedy coś takiego reinterpret_cast<unsigned char*>(&f)[i]
zostanie dobrze zdefiniowane.
W C ++ 20, możemy użyć std::array
z std::bit_cast
,
float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
zamiast tablicy w stylu C, aby uzyskać bajty float
?
źródło
struct X { unsigned char elems[5]; };
spełnia regułę, którą przytaczasz. Z pewnością można go zainicjować listą z maksymalnie 4 elementami. Można go również zainicjować listą z 5 elementami. Nie sądzę, żeby jakikolwiek standardowy implementator biblioteki nienawidził ludzi wystarczająco, by to zrobić, ale myślę, że jest to technicznie zgodne.elems[5]
. I w tym momencie nie widzę, jak możesz skończyć z agregatem gdziesizeof(array<char, sizeof(T)>) != sizeof(T)
?struct X { unsigned char c1, c2, c3, c4; };
lub drugiestruct X { unsigned char elems[4]; };
- chociaż znaki muszą być elementami tego agregatu, to pozwala im być bezpośrednimi elementami agregującymi lub elementy pojedynczego agregatu.P -> Q
nie implikuje niczego w sprawie, w której!P
array
sam nie będzie miał wypełnienia. Implementacje mogą nie mieć wypełnienia (a wszelkie implementacje, które to robią, należy uznać za dysfunkcyjne), ale nie ma gwarancji, żearray
samo nie będzie.Przyjęta odpowiedź jest nieprawidłowa, ponieważ nie uwzględnia problemów z wyrównaniem i dopełnianiem.
Na [tablicę] / 1-3 :
Norma tak naprawdę nie wymaga
std::array
posiadania dokładnie jednego publicznego elementu danych typuT[N]
, więc teoretycznie możliwe jest, żesizeof(To) != sizeof(From)
lubis_trivially_copyable_v<To>
.Będę jednak zaskoczony, jeśli to nie zadziała w praktyce.
źródło
Tak.
Zgodnie z artykułem opisującym zachowanie
std::bit_cast
i jego proponowaną implementacją, o ile oba typy mają ten sam rozmiar i są w trywialny sposób kopiowalne, rzutowanie powinno zakończyć się powodzeniem.Uproszczona implementacja
std::bit_cast
powinna wyglądać następująco:Ponieważ pływak (4 bajty) oraz tablicę
unsigned char
zsize_of(float)
spełniają wszystkich tych twierdzi bazowegostd::memcpy
zostaną przeprowadzone. Dlatego każdy element w wynikowej tablicy będzie jednym kolejnym bajtem liczby zmiennoprzecinkowej.Aby udowodnić to zachowanie, napisałem mały przykład w Eksploratorze kompilatorów, który możesz wypróbować tutaj: https://godbolt.org/z/4G21zS . Liczba zmiennoprzecinkowa 5.0 jest poprawnie przechowywana jako tablica bajtów (
Ox40a00000
), która odpowiada szesnastkowej reprezentacji tej liczby zmiennoprzecinkowej w Big Endian .źródło
std::array
nie będziesz mieć bitów wypełniających itp.?auto bits = reinterpret_cast<std::array<unsigned char, sizeof(float)>&>(f)
i uzyskiwać dokładnie takie same dane wyjściowe. Czy to coś dowodzi?std::array
spełnia wymagania ContiguiosContainer (od C ++ 17) .std::vector
spełnia również te same kryteria i oczywiście nie można go tutaj zastosować. Czy jest coś, co wymagastd::array
trzymania elementów wewnątrz klasy (w polu), co uniemożliwia, że jest prostym wskaźnikiem do wewnętrznej tablicy? (jak w wektorze, który ma również rozmiar, którego tablica nie musi mieć w polu)std::array
efektywnego wymaga przechowywania elementów w środku, ale martwię się problemami z układem.