2012-11-08 14 views
8

Powiel możliwe:
Aliasing `T*` with `char*` is allowed. Is it also allowed the other way around?Czy jest to niezdefiniowane zachowanie std :: array?

Używam std::array z char s trzymać wartość nieznanego prymitywnego typu, który jest długo nie więcej niż 10 bajtów, tak jak poniżej:

std::array<char, 10> val; 
*reinterpret_cast<double*>(val.data()) = 6.3; 
//blah blah blah... 
double stuff = *reinterpret_cast<double*>(val.data()); 

Czytałem, że odlew iz powrotem przez char * nie jest u ndefined, ponieważ kompilator zakłada, że ​​char * może aliasować wartość dowolnego typu. Czy to nadal działa, gdy wartość jest umieszczona w (jak zakładam jest) tablica z char s wewnątrz obiektu?

Uwaga: zdaję sobie sprawę, że mógłbym używać tutaj związku, ale w wyniku tego powstałyby duże ilości kodu dla tego, co robię, i chciałbym go w razie potrzeby uniknąć, stąd pytanie.

+0

Różne pytanie, ta sama odpowiedź. – Dan

+0

To samo pytanie, różne słowa. ; -] – ildjarn

Odpowiedz

13

Tak, std::array< char, 10 > nie spełnia wymagań wyrównania double, dzięki czemu reinterpret_cast prowokuje UB.

Zamiast tego spróbuj std::aligned_storage.

+0

Wyrównanie! Oczywiście, coś mi nawet nie przyszło do głowy. Dzięki za ten link, właśnie tego potrzebowałem. – Dan

0

To nie ma znaczenia, co jest zawarte w tablicy.

standardowego nawet nie rozważyć, co otacza coś (to nic, że podstawowy), ale robi konwersję wsparcia do/z char sekwencji.

Aby wykonać to bezpośrednio przez reinterpret_cast i przypisanie, należy poprawnie ustawić bufor.

Alternatywą jest użycie memcpy, która nie dba o wyrównanie.

W przypadku pokrewnego problemu ogólnie nie jest dobrym pomysłem przejście na poziom binarny. Na przykład prosta zmiana wersji kompilatora może uniemożliwić dostęp do pliku z serializacją binarną. Głównym powodem, dla którego to robimy, są surowe względy wydajności.

+0

Czy obsługuje konwersję arbitralnego "char *" na "double *"? Myślę, że konwersja wskaźnika może być stratna. Rozważmy ABI o różnej wielkości wskaźnikach. – Potatoswatter

+0

Jaki rodzaj zmiany kompilatora może spowodować to? – Dan

+0

Znacznik "char" ma tak dokładną rozdzielczość adresowania, jak dowolny wskaźnik, tak samo jak w przypadku "void". Konwersja wskaźnika może być stratna, jeśli bufor nie jest prawidłowo wyrównany. W każdym razie kopiowanie danych może być * nieefektywne *. –

Powiązane problemy