2012-04-03 23 views
5

I mają strukturę, która ma na celu przechowywania danych określonych przez użytkownika (to jest z wtyczką). Ma taki char[] z danym maksymalnym rozmiarem, aby przechowywać te dane.Typ paronomazja char [] i dereferencing

struct A 
{ 
    // other members omitted 
    // data meant to be type punned, only contains PODs 
    char data[256]; 
}; 

Potem jest struktura użytkownik próbka, która ma statyczną funkcję do oddania się od A.

struct B 
{ 
    int i; 
    double d; 

    static B& FromA_ref(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return * reinterpret_cast<B*>(a.data); 
    } 
}; 

Kompiluję z g++ -O3 -std=c++0x -Wall -o test test.cpp (GCC 4.6.1).

Spowoduje to wygenerowanie ostrzeżenia o numerze dereferencing type-punned pointer will break strict-aliasing rules. Myślałem, że będzie dobrze, ponieważ użyłem char[] jako pamięci masowej, która według mnie byłaby zgodna z tymi samymi regułami, co char*. Uważam to za dziwne, że tak nie jest. Czy nie? Cóż ... Nie mogę tego teraz zmienić, więc przejdźmy dalej.

Teraz rozważmy następujący sposób:

struct B 
{ 
    .... 
    static B* FromA_ptr(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return reinterpret_cast<B*>(a.data); 
    } 
} 

Ponieważ nie jestem dereferencji niczego tutaj GCC nie żadnego ostrzeżenia wyjście. Nie dzieje się tak również wtedy, gdy później używam wskaźnika do B.

A a; 
auto b = B::FromA_ptr(a); 
b->i = 2; // no warnings. 

Ale czy można to bezpiecznie zrobić? Czuję, że pracuję nad rozwiązaniem problemu, zamiast go rozwiązywać. Dla mnie -> nadal w jakiś sposób usuwa odwołanie do zmiennej.

Czy istnieje lepszy sposób osiągnięcia tego efektu? TO ZNACZY. otrzymasz modyfikowalne odniesienie (lub wskaźnik) odlane z magazynu wewnątrz innej struktury? (Unia nie będzie działać, ponieważ zbiór przechowywanych typów nie jest znany, gdy zdefiniowano A, a niektóre mogą być dodane za pomocą wtyczek, memcpy zmusi mnie do skopiowania danych tam iz powrotem, chociaż wydaje się, że jest to jedyny bezpieczny sposób, więc daleko)

+0

Nie jestem ekspertem, ale czy szukasz atrybutu '__may_alias__'? http://blog.worldofcoding.com/2010/02/solving-gcc-44-strict-aliasing-problems.html –

+0

W każdym razie, jak sobie radzisz z problemem wyrównania? – curiousguy

+0

@cualnyguy: do tej pory nie, ale powinienem. Na x86 myślę, że może pogorszyć wydajność w najgorszym. Mam nadzieję, że '__attribute __ ((wyrównane (8));' byłoby wystarczające, ponieważ nie próbuję automatycznie wektoryzować czegokolwiek. Prawdopodobnie "may_alias" już mówi GCC, aby zwracał uwagę na wyrównanie, zanim zrobi zbyt wiele dziwnych rzeczy. –

Odpowiedz

3

odpowiedź brzmi nie, to nie jest bezpieczne (zobacz SO question)

GCC zakłada, że ​​wskaźniki nie mogą alias. Na przykład, jeśli przypiszesz jeden, a następnie odczytasz od drugiego, GCC może, jako optymalizacja, zmienić kolejność odczytu i zapisu - widziałem to w kodzie produkcyjnym, nie jest przyjemne debugowanie.

atrybut ((may_alias)) w sprawie rodzajów stosowanych jest prawdopodobnie najbliżej można dostać do uszkodzenia założenie dla danej sekcji kodu.