Frage

Ich habe ein C ++ Programm einen TCP-Header als Struktur repräsentiert:

#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;
}

Wenn ich laufe dieses Programm ich die Größe dieser Header erhalten als 24 Bytes, die nicht die Größe, die ich erwartet hatte. Wenn ich den Typ des Feldes „wWindow“ auf „unsigned int wWindow: 16“ ändern, die die gleiche Anzahl von Bits als unsigned short hat, sagt mir das Programm die Größe der Struktur ist nun 20 Bytes, die richtige Größe. Warum ist das?

Ich bin mit Microsoft Visual Studio 2005 mit SP1 auf einer 32-Bit-x86-Maschine.

War es hilfreich?

Lösung

Sehen Sie diese Frage: Warum gleich die Summe ist nicht für eine Struktur sizeof sizeof jedes Mitglied? .

Ich glaube, dass Compiler einen Hinweis nimmt padding zu deaktivieren, wenn Sie die "unsigned int wWindow: 16". Syntax

Beachten Sie auch, dass eine kurze nicht 16 Bit sein garantiert. Die Garantie ist, dass. 16 Bit <= Größe einer kurzen <= Größe eines int

Andere Tipps

Da die Compiler Ihre bitfield in ein 32-Bit-int sind die Verpackung, keine 16-Bit-Einheit.

In der Regel sollten Sie bitfields vermeiden und verwenden andere Konstanten, (Aufzählungen oder was auch immer) mit expliziter Bit-Maskierung und Verschieben der ‚Unterfelder‘ für den Zugriff auf in einem Feld.

Hier ist ein Grund, warum bitfields sollte vermieden werden - sie zwischen Compiler sogar für die gleiche Plattform nicht sehr portabel sind. aus dem C99-Standard (es gibt eine ähnliche Formulierung in dem C90-Standard):

  

Eine Implementierung zuteilen kann jeder   adressierbare Speichereinheit groß genug   einen bitfield zu halten. Wenn genügend Platz   ein Bitfeld bleibt, die sofort   folgt ein weiteres Bit-Feld in einem   Struktur wird in verpackt werden   benachbarte Bits der gleichen Einheit. Wenn   nicht genügend Platz bleibt, ob ein   Bit-Feld, das nicht paßt setzen   in die nächste Einheit oder Überlappungen   benachbarte Einheiten sind   Implementierung definiert. Die Reihenfolge von   Zuordnung von Bit-Felder innerhalb einer Einheit   (Hohe Ordnung zu niedriger Ordnung oder niedrige Ordnung   zu hohen Ordnung) ist   Implementierung definiert. die Ausrichtung   Einheit des adressierbaren Speicher ist   nicht näher bezeichnet.

Sie können nicht garantieren, ob ein Bit-Feld wird ‚Spanne‘ int Grenze oder nicht und Sie können nicht angeben, ob ein Bitfeld im Low-End des int beginnt oder dem oberen Ende des int (dies ist unabhängig davon, ob der Prozessor ist big-endian oder little-endian).

Ihre Reihe von "unsigned int: xx" bitfields aufbrauchen nur 16 der 32 Bits in einem int. Die anderen 16 Bits (2 Bytes) gibt es, aber nicht verwendet. Dies wird durch die unsigned short gefolgt, die auf einer int Grenze ist, und dann wird ein Wort, das mit auf einer int-Grenze ausgerichtet ist, was bedeutet, dass es 2 Bytes padding zwischen ihnen.

Wenn Sie umschalten auf „unsigned int wWindow: 16“, statt eine separate kurz ist, verwendet der Compiler die nicht benötigten Teile des früheren bitfield, so dass keine Abfälle, keine kurz, und keine Polsterung nach dem kurzen, Sie damit sparen vier Bytes.

Der Compiler ist Klotzen des nicht-Bitfeld struct Mitglied zu 32-Bit - Mutterwortausrichtung. Um dies zu beheben, gehen Sie #pragma pack (0) vor der Struktur und #pragma pack () nach.

Struct Grenzen im Speicher können durch den Compiler aufgefüllt werden, abhängig von der Größe und Reihenfolge der Felder.

Nicht eine C / C ++ Experte, wenn es um Verpackung kommt. Aber ich denke, es gibt eine Regel in der Spezifikation, die besagt, dass, wenn ein Nicht-Bit-Feld ein bitfield folgt an der Wortgrenze ausgerichtet sein muss, unabhängig davon, ob sie paßt in dem verbleibenden Raum. Durch sie eine explizite Bitvektor machen Sie vermeiden dieses Problem.

Auch das ist Spekulation mit einem Hauch von Erfahrung.

Interessant -. Ich würde denken, dass „WORD“ würde bewerten zu „unsigned short“, so dass Sie dieses Problem in mehr als ein Ort haben würden

Beachten Sie auch, dass Sie mit Endian Punkten in jedem Wert über 8 Bits beschäftigen werden müssen.

Ich denke, Mike B es richtig, aber doch nicht ganz klar. Wenn Sie für „short“ fragen, ist es auf 32-Bit-Grenze ausgerichtet. Wenn Sie sich für int fragen: 16, ist es nicht. So int. 16 passt genau nach th ebit Felder, während kurze Sprünge 2 Bytes und beginnt an der nächsten 32-Bit-Block

Der Rest von dem, was er sagt, ist vollkommen zutreffend - das Bitfeld darf niemals eine von außen sichtbare Struktur zu codieren verwendet werden, da es keine Garantie gibt, wie sie zugeordnet sind. Am besten, sie gehören Programmen in eingebettet, wo ein Byte Speicher wichtig ist. Und selbst dort, man kann sich nicht verwenden, um tatsächlich controlY Bits in memory-mapped Ports.

Sie sehen verschiedene Werte wegen der Compiler Verpackung Regeln. Sie können Regeln spezifisch für Visual Studio finden Sie unter hier .

Wenn Sie eine Struktur haben, die verpackt werden müssen (auf einige spezifische Ausrichtungsanforderungen oder halten), sollten Sie die #pragma pack () Option verwenden. Für Ihren Code können Sie #pragma pack (0) verwendet werden, die alle Strukturelemente auf Byte-Grenzen ausgerichtet werden. Sie können dann #pragma pack () verwenden Struktur Verpackung zurückgesetzt, um es Standardzustand ist. Sie können weitere Informationen auf der Packung Pragma hier .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top