Ottenere diverse dimensioni dell'intestazione modificando le dimensioni della finestra

StackOverflow https://stackoverflow.com/questions/149995

  •  02-07-2019
  •  | 
  •  

Domanda

Ho un programma C ++ che rappresenta un'intestazione TCP come struct:

#include "stdafx.h"

/*  TCP HEADER

    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

*/

typedef struct {        // RFC793
    WORD         wSourcePort;
    WORD         wDestPort;
    DWORD        dwSequence;
    DWORD        dwAcknowledgment;
    unsigned int byReserved1:4;
    unsigned int byDataOffset:4;
    unsigned int fFIN:1;
    unsigned int fSYN:1;
    unsigned int fRST:1;
    unsigned int fPSH:1;
    unsigned int fACK:1;
    unsigned int fURG:1;
    unsigned int byReserved2:2;
    unsigned short wWindow;
    WORD         wChecksum;
    WORD         wUrgentPointer;
} TCP_HEADER, *PTCP_HEADER;


int _tmain(int argc, _TCHAR* argv[])
{
    printf("TCP header length: %d\n", sizeof(TCP_HEADER));
    return 0;
}

Se eseguo questo programma ottengo la dimensione di questa intestazione come 24 byte, che non è la dimensione che mi aspettavo. Se cambio il tipo di campo & Quot; wWindow & Quot; a " unsigned int wWindow: 16 " ;, che ha lo stesso numero di bit di un short senza segno, il programma mi dice che la dimensione della struttura è ora di 20 byte, la dimensione corretta. Perché questo?

Sto utilizzando Microsoft Visual Studio 2005 con SP1 su una macchina x86 a 32 bit.

È stato utile?

Soluzione

Vedi questa domanda: Perché sizeof per una struttura non è uguale alla somma di sizeof di ciascun membro? .

Credo che il compilatore prenda un suggerimento per disabilitare il riempimento quando si usa " unsigned int wWindow: 16 " sintassi.

Inoltre, si noti che non è garantito che un corto sia di 16 bit. La garanzia è che: 16 bit & Lt; = size of a short & Lt; = size of an int.

Altri suggerimenti

Perché il compilatore sta comprimendo il tuo bitfield in un int a 32 bit, non in un'entità a 16 bit.

In generale dovresti evitare i bitfield e usare altre costanti manifest (enum o quant'altro) con mascheramento e spostamento dei bit espliciti per accedere ai "sottocampi" in un campo.

Ecco un motivo per cui i bitfield dovrebbero essere evitati: non sono molto portatili tra i compilatori anche per la stessa piattaforma. dallo standard C99 (c'è una formulazione simile nello standard C90):

  

Un'implementazione può allocare qualsiasi   unità di archiviazione indirizzabile abbastanza grande   per tenere un bitfield. Se abbastanza spazio   rimane, un bit-field che immediatamente   segue un altro campo bit in a   la struttura deve essere imballata in   bit adiacenti della stessa unità. Se   rimane spazio insufficiente, sia a   viene inserito un campo bit che non si adatta   nell'unità successiva o si sovrappone   unità adiacenti è   implementazione definita. L'ordine di   allocazione di campi bit all'interno di un'unità   (da alto a basso o basso   all'ordine elevato) è   implementazione definita. L'allineamento   dell'unità di archiviazione indirizzabile è   non specificato.

Non puoi garantire se un campo di bit 'si estenda' su un limite di int o no e non puoi specificare se un campo di bit inizia dalla parte bassa dell'int o dalla parte alta dell'int (questo è indipendente dal fatto che il processore è big-endian o little-endian).

La tua serie di " unsigned int: xx " i bitfield utilizzano solo 16 dei 32 bit in un int. Gli altri 16 bit (2 byte) sono presenti, ma non utilizzati. Questo è seguito dal corto senza segno, che si trova su un confine int, e quindi da una WORD, che è allineata su un confine int, il che significa che ci sono 2 byte di riempimento tra di loro.

Quando passi a " unsigned int wWindow: 16 " ;, invece di essere un corto separato, il compilatore usa le parti inutilizzate del bitfield precedente, quindi niente spreco, niente corto e no imbottitura dopo il corto, quindi risparmi quattro byte.

Il compilatore sta riempiendo il membro struct non bitfield a 32 bit - allineamento delle parole nativo. Per risolvere questo problema, esegui #pragma pack (0) prima di struct e #pragma pack () dopo.

I limiti di Struct in memoria possono essere riempiti dal compilatore in base alla dimensione e all'ordine dei campi.

Non è un esperto C / C ++ per quanto riguarda l'imballaggio. Ma immagino che ci sia una regola nella specifica che dice che quando un non-bitfield segue un bitfield deve essere allineato sul confine della parola indipendentemente dal fatto che si adatti o meno allo spazio rimanente. Rendendolo un bitvector esplicito stai evitando questo problema.

Anche in questo caso si tratta di speculazioni con un tocco di esperienza.

Interessante - Penso che " WORD " valuterebbe " unsigned short " ;, quindi avresti quel problema in più di un posto.

Inoltre, tieni presente che dovrai affrontare i problemi di endian con qualsiasi valore superiore a 8 bit.

Penso che Mike B abbia capito bene, ma non è del tutto chiaro. Quando chiedi & Quot; short & Quot ;, è allineato sul confine a 32 bit. Quando chiedi int: 16, non lo è. Quindi int: 16 si inserisce subito dopo i campi ebit, mentre short salta 2 byte e inizia al successivo blocco a 32 bit.

Il resto di ciò che sta dicendo è perfettamente applicabile - il campo bit non deve mai essere usato per codificare una struttura visibile esternamente, perché non ci sono garanzie su come siano allocati. Nella migliore delle ipotesi, appartengono a programmi integrati in cui è importante salvare un byte. E anche lì, non puoi usarli per controllare effettivamente i bit nelle porte mappate in memoria.

Stai visualizzando valori diversi a causa delle regole di imballaggio del compilatore. Puoi vedere le regole specifiche per Visual Studio qui .

Quando si dispone di una struttura che deve essere imballata (o aderire ad alcuni requisiti di allineamento specifici), è necessario utilizzare l'opzione #pragma pack (). Per il tuo codice, puoi usare #pragma pack (0) che allineerà tutti i membri della struttura sui confini dei byte. È quindi possibile utilizzare #pragma pack () per reimpostare l'imballaggio della struttura allo stato predefinito. Puoi vedere maggiori informazioni sul pacchetto pragma qui .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top