2010-08-12 8 views
11

Mam kodu, który wygląda mniej więcej tak, gdzie addr jest sockaddr *:dereferencji wskaźnik łamie surowe przepisy anty-aliasingu za pomocą gniazd Berkeley

struct sockaddr_in *sin = (struct sockaddr_in *) addr; 
const char *IP=inet_ntoa(sin -> sin_addr); 

Uważam, że to bardzo typowy kod za korzystanie Berkeley gniazda.

Jednak, kiedy mogę skompilować to, Dostaję następujące ostrzeżenie:
dereferencing pointer 'sin' does break strict anti-aliasing rules

szukają w internecie, znajdę jakąś dyskusję o tym, że droga Robię rzeczy jest dość typowe, ale ten Ostrzeżenie dla kompilatora również jest całkiem realne i nie jest dobre.

Jaki jest właściwy sposób ponownego napisania tego kodu, aby naprawić ostrzeżenie, a nie tylko go wyciszyć?

Odpowiedz

-2

Jeśli plik nagłówkowy i kompilator są częścią tej samej implementacji C lub C++, zgłoś się do dostawcy i poproś o umieszczenie odpowiedniego #pragma w pliku nagłówkowym, aby uciszyć ich kompilator. Jako implementator mogą grać w takie gry, o ile zapewniają zgodną implementację.

Jeśli twój plik nagłówkowy i kompilator pochodzą z dwóch oddzielnych implementacji C lub C++, masz szczęście, że wszystko działa tak dobrze, jak one, i musisz rozwiązać to samodzielnie.

+1

Gniazda nie są częścią implementacji kompilatora, ale część systemu operacyjnego. –

+0

Gdzie programista ma "#include ", albo ten plik nagłówkowy coś.h jest częścią implementacji C lub C++, albo programista ma szczęście, że rzeczy działają tak dobrze jak one, a programista musi sam je rozwiązać. –

+1

Dotyczy to tylko plików #include należących do języka, np. stdlib.h. Pliki dołączane do gniazd są częścią zestawu gniazd SDK, a nie kompilatora. – EJP

1

W zależności od sposobu użycia struct sockaddr, myślę, że albo Twój kod jest uszkodzony, albo gcc jest zepsuty. struct sockaddr i mają wspólny początkowy element (sa_family/sin_family), więc nie naruszają reguł aliasingu, jeśli dostęp do tego elementu odbywa się tylko przez oba wskaźniki; uczynienie tego jest dozwolone przez C99. Ponadto struct sockaddr nie ma innych elementów, do których masz dostęp. Jest to w dużej mierze rodzaj nieprzejrzysty dla prymitywnego polimorfizmu adresu gniazda. Jeśli kręciłeś się w wewnętrznych partycjach związanych z implementacją w struct sockaddr, lub jeszcze gorzej, jeśli zadeklarowałeś obiekt struct sockaddr, a nie tylko wskaźnik lub wykonane kopiowanie pomiędzy takimi obiektami, Twój kod jest uszkodzony. Jeśli nie, a gcc ostrzega, że ​​złamałeś zasady aliasów, generowanie ostrzeżeń gcc jest zepsute. Na pewno nie zdziwiłbym się, gdyby to było drugie.

+1

@R. najpierw nie sądzę, że jest powiedziane, że "sa_family/sin_family" jest typowym początkowym elementem. Muszą być obecne zarówno z identycznymi wartościami. Wtedy dostęp jako OP podał go * jest * naruszeniem zasad aliasingu, w zasadzie robi '((struct sockaddr_in *) addr) -> sin_addr' co jest typowym idiomem do robienia takich rzeczy. –

+0

Przesyłanie wskaźnika, a następnie jego dereferencja, to ** nigdy ** naruszenie zasad aliasingu. Tylko jeśli dereferencje zostały usunięte, chociaż oryginalny typ może zostać naruszony przez reguły aliasingu. Niezależnie od tego, czy POSIX gwarantuje, że '* _family' jest powszechnym elementem początkowym, w praktyce jest to **, a gcc, o definicji struktury, wie o tym. Tak więc moje twierdzenie o naruszeniu zasad aliasingu jest poprawne. –

+0

"Muszą być obecne obie, z identycznymi wartościami" nic nie znaczą. Mówisz o tej samej pamięci. Oczywiście wartości są takie same. – EJP

2

Tak, jest to znany problem z gcc i gniazdami. Problem w zasadzie wydaje się taki, że sposób, w jaki zaprojektowano ten ip [46], jest niezgodny z założeniami, które ludzie gcc sądzą, że mogą wydedukować o aliasingu wskaźników.

zwykle uciec z tego najpierw biorąc wskaźnik na struct

struct in_addr* act = &(sin->sin_addr); 

a następnie za pomocą *act.

+1

Jeśli gcc nie daje tego samego ostrzeżenia, gdy używasz * act, nie włączono tych samych ostrzeżeń co oryginalny plakat, lub znalazłeś błąd w gcc. –

5

Miałem ten sam problem - wygląda na błąd w gcc.

udało mi się obejść za pomocą

(*sin).sin_addr 

zamiast

sin->sin_addr 
Powiązane problemy