2010-08-12 2 views
11

c'ho codice che assomigli a questo, dove addr è un sockaddr *:puntatore Dereferencing fa rompere severe norme anti-aliasing utilizzando i socket Berkeley

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

Credo che questo è un codice molto tipico per l'utilizzo di Berkeley prese.

Tuttavia, quando compilo questo, sto ottenendo il seguente avviso:
dereferencing pointer 'sin' does break strict anti-aliasing rules

Ricerca on-line, ho trovato qualche discussione il fatto che il modo in cui sto facendo le cose è abbastanza tipico, ma questo anche l'avviso del compilatore è abbastanza reale e non una buona cosa.

Qual è il modo corretto di ripetere questo codice per correggere l'avviso, e non solo per silenziarlo?

risposta

-2

Se il file di intestazione e il compilatore sono entrambi parti della stessa implementazione C o C++, rivolgersi al fornitore e chiedere di inserire un #pragma appropriato nel proprio file di intestazione per disattivare il compilatore. Come implementatore, possono giocare a giochi del genere, purché forniscano un'implementazione conforme.

Se il tuo file di intestazione e il tuo compilatore provenivano da due implementazioni C o C++ separate, sei fortunato che le cose funzionino bene come loro, e tu devi risolverlo da solo.

+1

prese di corrente non sono parte di un'implementazione del compilatore, ma parte del sistema operativo. –

+0

Se il programmatore ha "#include ", o quel file di intestazione qualcosa.h fa parte di un'implementazione C o C++, oppure il programmatore è fortunato che le cose funzionino bene come fanno e il programmatore deve risolverlo da sé. –

+1

Questo vale solo per i file #include che fanno parte della lingua, ad es. stdlib.h. I file di socket includono parte di un SDK di socket, non del compilatore. – EJP

1

A seconda di come hai usato struct sockaddr, penso che il tuo codice sia rotto, o gcc è rotto. struct sockaddr e struct sockaddr_in hanno un elemento iniziale comune (sa_family/sin_family) in modo da non violare le regole di aliasing se si accede a questo elemento solo tramite entrambi i puntatori; farlo è permesso da C99. Inoltre, struct sockaddr non ha altri elementi a cui è consentito accedere. È in gran parte un tipo opaco per il polimorfismo di indirizzo socket primitivo. Se si è passati a interni interni specifici dell'implementazione in struct sockaddr o, peggio ancora, se si dichiarava un oggetto struct sockaddr anziché un puntatore o si eseguiva la copia tra tali oggetti, il codice non funzionava. Se non lo hai fatto, e gcc sta dando un avvertimento affermando che hai violato le regole di aliasing, quindi la generazione di avvisi di gcc è stata interrotta. Sicuramente non sarei sorpreso se fosse il secondo.

+1

@R. per prima cosa non penso che si affermi che 'sa_family/sin_family' è un elemento iniziale comune. Devono essere presenti entrambi, con valori identici. Quindi l'accesso come l'OP gli ha dato * è * una violazione delle regole di aliasing, in pratica sta facendo '((struct sockaddr_in *) addr) -> sin_addr' che è un linguaggio comune per fare queste cose. –

+0

Lanciare un puntatore e quindi dereferenziare è, di per sé, ** mai ** una violazione delle regole di aliasing. Solo se hai anche effettuato il dereferenziamento anche se il tipo originale può essere violato le regole di aliasing. Indipendentemente dal fatto che POSIX garantisca che '* _family' sia un elemento iniziale comune, in pratica è ** **, e gcc, che ha la definizione della struttura, lo sa. Quindi la mia affermazione sul fatto che nessuna regola di aliasing sia stata violata è corretta. –

+0

'Devono essere presenti entrambi, con valori identici' non significa nulla. Stai parlando dello stesso pezzo di memoria. Ovviamente i valori sono gli stessi. – EJP

2

Sì, questo è un problema noto con gcc e socket. Il problema fondamentalmente sembra essere che il modo in cui questa roba [46] è progettata sia incompatibile con le ipotesi che le persone di gcc pensano di poter dedurre circa l'aliasing dei puntatori.

Io di solito farla franca con questo prendendo un puntatore sul struct

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

e quindi utilizzando *act.

+1

Se gcc non ti dà lo stesso avviso quando usi * act, o non hai abilitato gli stessi avvertimenti del poster originale, o hai trovato un bug in gcc. –

5

Ho avuto lo stesso problema: sembra un bug in gcc.

sono stato in grado di ottenere intorno ad esso utilizzando

(*sin).sin_addr 

invece di

sin->sin_addr