2013-04-15 26 views
5

ho una struttura come questaserie typecast a struct in C

struct packet 
{ 
int seqnum; 
char type[1]; 
float time1; 
float pri; 
float time2; 
unsigned char data[512]; 
} 

ricevo pacchetto in un array

char buf[529]; 

voglio prendere il seqnum, i dati tutto separately.Does il seguente lavoro typecast .. Sta dando valore spazzatura per me.

struct packet *pkt; 
pkt=(struct packet *)buf; 
printf(" %d",pkt->seqnum) 
+0

prova a leggere il buon numero di byte: 'char buf [sizeof (struct pacchetto)];' e con: 'leggi (fd, buf, sizeof (struct packet)); ' – Marcassin

+2

@Marcassin: questo garantisce che il numero di byte letti sia uguale alla dimensione della struttura, ma non cambia i byte in ingresso e quindi non fa nulla per assicurare che abbiano padding o endianness che corrispondono al struttura. Se i byte in ingresso non hanno tre byte tra 'char type [1]' e 'float time1' ma la struttura lo fa, allora' read' è completamente rotto. –

+0

Per motivi di bellezza, non digitare mai la frase "Please help me with the code." – Rerito

risposta

7

No, è probabile che non funzionerà ed è generalmente un modo brutto e rotto di farlo.

È necessario utilizzare estensioni specifiche del compilatore per assicurarsi che non vi siano padding invisibili tra i membri della struct, perché qualcosa del genere funzioni. Con gcc, ad esempio, lo fai usando la sintassi __attribute__().

Non è, quindi, un'idea portatile.

È molto meglio essere espliciti e decomprimere ogni campo. Questo ti dà anche la possibilità di avere un ben definito endianness nel tuo protocollo di rete, che è generalmente una buona idea per l'interoperabilità.

+0

Ciao grazie. puoi dire come decomprimere ogni campo nell'esempio sopra. – user1762571

4

No, questo non è un codice generalmente valido. Si dovrebbe fare prima la struct e poi la memcopy:

packet p; 

memcpy(&p.seqnum, buf + 0, 4); 

memcpy(&p.type[0], buf + 4, 1); 

memcpy(&p.time1, buf + 5, 4); 

E così via.

È necessario prestare molta attenzione per ottenere le dimensioni del tipo e l'endianità corrette.

1

Prima di tutto, non è possibile sapere in anticipo dove il compilatore inserirà i byte di riempimento nella struttura per l'ottimizzazione delle prestazioni (allineamento riga cache, allineamento intero ecc.) In quanto dipende dalla piattaforma. Tranne, ovviamente, se stai pensando di creare l'app solo sulla tua piattaforma.

Ad ogni modo, nel tuo caso sembra che tu stia ricevendo dati da qualche parte (rete?) Ed è altamente probabile che i dati siano stati compressi (nessun byte di riempimento tra i campi).

Se si desidera tipograficamente la matrice su un puntatore di struttura, è comunque possibile indicare al compilatore di rimuovere i byte di riempimento che potrebbe aggiungere. Si noti che questo dipende dal compilatore che si usa e non è un'implementazione C standard. Con gcc, si potrebbe aggiungere questo dichiarazione alla fine della vostra definizione della struttura:

struct my_struct { 
    int blah; 
    /* Blah ... */ 
} __attribute__((packed)); 

Nota che interesserà le prestazioni per l'accesso utente, copiare ecc ...

Se non avete una buona ragione per fare ciò, non usare mai la cosa __attribute__((packed))!

L'altra soluzione, che è molto più consigliabile, è quella di eseguire l'analisi autonomamente. Basta allocare una struttura appropriata e riempire i suoi campi cercando le buone informazioni dal proprio buffer.È probabile che una sequenza di istruzioni memcpy faccia il trucco qui (vedere la risposta di Kerrek)

+0

Il '__attribute __ ((packed))' specifico del compilatore non è C standard, ma sarà comunque valido se lo stesso compilatore viene utilizzato su più piattaforme. A proposito, il contesto dell'OP sembra implicare del codice relativo alla rete e, quindi, i pacchetti sono impacchettati da qui il suggerimento. – Rerito

+0

@EricPostpischil Ho modificato la mia risposta per renderla più chiara. La cosa '__attribute__' limita la portabilità di uno snippet di codice nel senso che alcuni compilatori potrebbero non integrare gli attributi richiesti, ma se lo stesso compilatore viene utilizzato in tutte le piattaforme, c'è ancora la portabilità tra _platforms_? (Chiedo questo per cancellare la mia mente :)) – Rerito

+1

Se è supportato, '__attribute __ ((packed))' risolve il problema di padding ma non i problemi di endianness o altri problemi su come i valori sono codificati/rappresentati (ad es. 'type usa IEEE 754 o quanto è grande il tipo' int'). Ci sono due modi per risolvere questo problema: Scrivere in C standard, leggere ciascun byte singolarmente e convertirlo in tipi nativi usando aritmetica eccetera, o scrivere per un'implementazione specifica e target con i byte nella 'struct' ** completamente ** definita e implementazione dipendente. –