2014-04-21 3 views
7

N379726,4 [complex.numbers] mówi o tym do odlewania std::complex<T>*T*Czy to jest legalne do oddania pływak * std :: kompleks <float> *

4 Ponadto, jeśli jest wyrazem typu cv std::complex<T>* a ekspresja a[i] jest dobrze zdefiniowana dla ekspresji całkowitej i, a następnie:
- reinterpret_cast<cv T*>(a)[2*i] wyznacza część rzeczywistą a[i] i
- reinterpret_cast<cv T*>(a)[2*i + 1] otrzymuje designat e wyobrażona część a[i].

Czy to (lub inne sformułowanie normy) implikuje, że mogę reinterpret_cast w inny sposób? Czy mogę to zrobić:

float * pf; 
    std::complex<float>* pc = reinterpret_cast<std::complex<float>*>(pf); 
    pc[i].real(); 

As n.m. wskazany poniżej, musiałbym się upewnić, że wyrównanie pf jest odpowiednie dla std::complex<float>. Można założyć, że się tym zajmuje.

+0

Wymogi dotyczące wyrównania dla "kompleksu " mogą być bardziej rygorystyczne niż "float". –

+0

@ n.m. Wystarczająco uczciwe, jak rozumiem, które można naprawić za pomocą 'std :: align' zgodnie z [to pytanie] (http://stackoverflow.com/questions/6973995/dynamic-aligned-memory-allocation-in-c11). – SirGuy

+0

legal, tak 'reinterpret_cast' zasadniczo po prostu mówi kompilacji, aby zinterpretować fragment pamięci jako dowolny typ. Bezpieczne ... o moje nie. – Mgetz

Odpowiedz

3

Nie, klauzula ta nie daje takiej gwarancji.

Teraz w praktyce najczęstszym problemem będzie wyrównanie: ale nawet to może być rzadkie.

Drugi problem polegałby na ścisłym aliasingu, w którym pamięć przydzielona jako double może zostać przyjęta przez kompilator, aby nie była modyfikowana przez żadną operację obejmującą wskaźniki do innych typów (z wyjątkiem char). Powyższe umieszcza ograniczenie kierujące się w drugą stronę (przydzielony wskaźnik complex może nie zakładać, że double* s nie wskazuje na jego dane), ale nie w wybranym kierunku. Ponownie jest to stosunkowo mało znane, ale kompilator może użyć tego do zmiany kolejności zapisów w kodzie.

Będzie to jednak zwykle działać. Częściej, jeśli ją wyrównasz, a twój kompilator nie stosuje ścisłych założeń aliasingu: nawet wtedy jest to niezdefiniowane zachowanie według standardu.

+0

Uzyskiwanie dostępu do członków 'std :: complex ' uzyskuje dostęp tylko do pamięci przez wskaźnik do 'double', więc nie widzę, jak ścisłe aliasing jest problemem. – SirGuy

+0

@guygreer 'std :: complex' nie zawiera wskaźnika do' double' w dowolnej implementacji, jaką mogę sobie wyobrazić. Ścisłe aliasing oznacza, że ​​'double * b = new double [2]; * b = 3,0; '(* (kompleks *) (b)) = kompleks (2); std :: cout << * b; 'może zmienić polecenie print na' std :: cout << 3.0; ', ponieważ narusza ścisłe aliasing. @guygreer – Yakk

+0

W ostatnim komentarzu są pewne literówki - miałem rzucać do złożonego wskaźnika.Chodzi mi o to, że aliasing musi działać tylko na typach kompatybilnych z układem: standard prawie, ale nie całkiem, gwarantuje kompatybilność układu pomiędzy złożonymi i dwa razy więcej 'podwójnymi' w tablicy. Należy pamiętać, że ten poziom skrętu może nie dotyczyć żadnego kompilatora, z którym kiedykolwiek pracowałeś. – Yakk

1

To nie działa w drugą stronę. A std::complex<float> to dwie kolejne wartości zapisane w pamięci, o czym świadczy standard, który pozwala na wykonanie, ale mamy wskaźnik do pojedynczej wartości zmiennoprzecinkowej i przekształcamy go w wskaźnik w strukturę, która powinna zawierać dwie zmienne. Nawet gdybyś miał dwie pływaki, standard nie gwarantuje tego i dlatego byłoby niezgodne z prawem do reinterpret_cast do wskaźników w tym kierunku.