문제

TCP 헤더를 구조체로 나타내는 C++ 프로그램이 있습니다.

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

이 프로그램을 실행하면 이 헤더의 크기가 24바이트로 표시되는데, 이는 예상했던 크기가 아닙니다."wWindow" 필드의 유형을 unsigned short와 동일한 비트 수를 갖는 "unsigned int wWindow:16"으로 변경하면 프로그램은 구조체의 크기가 이제 올바른 크기인 20바이트라고 알려줍니다.왜 이런거야?

32비트 x86 시스템에서 Microsoft Visual Studio 2005 SP1을 사용하고 있습니다.

도움이 되었습니까?

해결책

이 질문 참조 : 구조물의 크기가 각 멤버의 크기의 합과 같은 이유는 무엇입니까? .

"부호없는 int wwindow : 16"구문을 사용할 때 컴파일러가 패딩을 비활성화하려는 힌트를받는다고 생각합니다.

또한 짧은 것은 16 비트로 보장되지 않습니다. 보증은 다음과 같습니다. 16 비트 <= int의 짧은 <= 크기의 크기.

다른 팁

컴파일러가 비트 필드를 16 비트 엔티티가 아닌 32 비트 INT로 포장하고 있기 때문입니다.

일반적으로 비트 필드를 피하고 명시 적 비트 마스킹 및 이동과 함께 다른 매니페스트 상수 (열거 등)를 사용하여 필드의 '하위 필드'에 액세스해야합니다.

비트 필드를 피해야하는 이유 중 하나는 동일한 플랫폼에서도 컴파일러간에 휴대 할 수 없습니다. C99 표준에서 (C90 표준에 유사한 문구가 있습니다) :

구현은 비트 필드를 보유 할만 큼 큰 주소가 가능한 저장 장치를 할당 할 수 있습니다. 충분한 공간이 남아있는 경우, 구조물의 다른 비트 필드를 즉시 따르는 비트 필드는 동일한 장치의 인접한 비트로 포장되어야합니다. 공간이 충분하지 않은 경우, 맞지 않는 비트 필드가 다음 장치에 넣거나 인접한 단위가 겹치는지 여부는 구현 정의됩니다. 장치 내에서 비트 필드 할당 순서 (고차 또는 저차 또는 저차에서 고차로 저격자)가 구현되지 않았습니다. 주소 수성 저장 장치의 정렬은 지정되지 않습니다.

비트 필드가 INT 경계를 '스팬'하는지 여부를 보장 할 수 없으며 비트 필드가 INT의 낮은 엔드 또는 INT의 하이 엔드에서 시작하는지 여부를 지정할 수 없습니다 (이것은 프로세서가 있는지 여부와 독립적입니다. 빅 엔디 안 또는 리틀 엔디언).

일련의 "부호없는 int : xx"비트 필드는 int에서 32 비트 중 16 비트 만 사용합니다. 다른 16 비트 (2 바이트)는 있지만 사용되지 않습니다. 그 다음에는 int 경계에있는 서명되지 않은 단편이 뒤 따른 다음 단어는 int 경계에 정렬되어 있으며, 이는 그들 사이에 2 바이트의 패딩이 있음을 의미합니다.

"부호없는 int wwindow : 16"으로 전환하면 별도의 짧은 짧은 대신 컴파일러는 이전 비트 필드의 사용하지 않은 부분을 사용하므로 짧은 후에는 폐기물, 짧은 및 패딩이 없으므로 4 바이트를 절약합니다.

컴파일러는 비 비트 필드 구조물 멤버를 32 비트-기본 단어 정렬로 패딩합니다. 이 문제를 해결하려면 #pragma pack (0)을 구조물과 #pragma pack () 후에 수행하십시오.

메모리의 구조 경계는 필드의 크기와 순서에 따라 컴파일러에 의해 패딩 될 수 있습니다.

포장과 관련하여 C/C ++ 전문가가 아닙니다. 그러나 사양에는 비 비트 필드가 비트 필드를 따르면 나머지 공간에 적합한 지 여부에 관계없이 단어 경계에 정렬되어야한다고 말합니다. 명시적인 비트 벡터로 만들면이 문제를 피하고 있습니다.

다시 이것은 경험의 손길로 추측입니다.

흥미로운 - 나는 "단어"가 "서명되지 않은 짧은"것으로 평가 될 것이라고 생각할 것입니다.

또한 8 비트 이상의 값으로 엔디 언 문제를 처리해야합니다.

나는 Mike B가 옳았다고 생각하지만 완벽하게 명확하지는 않습니다."짧게"라고 하시면 32비트 경계에 맞춰져 있습니다.int:16을 요청하면 그렇지 않습니다.따라서 int:16은 ebit 필드 바로 뒤에 맞는 반면, short는 2바이트를 건너뛰고 다음 32비트 블록에서 시작합니다.

그가 말하는 나머지 부분은 완벽하게 적용 가능합니다. 비트 필드는 할당 방법에 대한 보장이 없기 때문에 외부에서 볼 수 있는 구조를 코딩하는 데 사용되어서는 안 됩니다.기껏해야 바이트 저장이 중요한 임베디드 프로그램에 속합니다.그리고 거기에서도 메모리 매핑된 포트의 비트를 실제로 제어하는 ​​데 사용할 수 없습니다.

컴파일러 포장 규칙으로 인해 다른 값이 나타납니다. Visual Studio와 관련된 규칙을 볼 수 있습니다 여기.

포장 해야하는 구조가 있거나 특정 정렬 요구 사항을 준수하는 경우 #Pragma Pack () 옵션을 사용해야합니다. 코드의 경우 바이트 경계에서 모든 구조 멤버를 정렬하는 #Pragma Pack (0)을 사용할 수 있습니다. 그런 다음 #pragma pack ()을 사용하여 기본 상태로 구조 포장을 재설정 할 수 있습니다. Pack Pragma에 대한 자세한 정보를 볼 수 있습니다 여기.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top