수색…


소개

기본적으로 C 컴파일러는 정렬되지 않은 액세스, DEC Alpha와 같은 RISC 시스템 및 일부 ARM CPU의 문제에 대한 처벌을받지 않고 각 구성원이 빠르게 액세스 할 수 있도록 구조를 배치합니다.

CPU 아키텍처 및 컴파일러에 따라 구조는 해당 구성 요소 멤버의 크기 합계보다 메모리에서 더 많은 공간을 차지할 수 있습니다. 컴파일러는 멤버간에 또는 구조의 끝에 패딩을 추가 할 수 있지만 처음에는 추가 할 수 없습니다.

패킹은 기본 패딩을 덮어 씁니다.

비고

에릭 레이몬드 (Eric Raymond)는 유용한 읽을 거리 인 C 구조 패킹의 잃어버린 기술 에 대한 기사를 갖고 있습니다.

포장 구조

기본적으로 구조체는 C로 채워져 있습니다.이 동작을 피하려면 명시 적으로 요청해야합니다. GCC에서는 __attribute__((__packed__)) 입니다. 64 비트 시스템에서이 예제를 고려하십시오.

struct foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

구조체는 자동으로 패딩되어 8-byte 정렬을 가지며 다음과 같이 보입니다 :

struct foo {
    char *p;     /* 8 bytes */
    char c;      /* 1 byte  */

    char pad[7]; /* 7 bytes added by compiler */

    long x;      /* 8 bytes */
};

sizeof(struct foo)17 대신에 24 를줍니다. 이것은 64 비트 컴파일러가 각 단계에서 8 바이트 단어로 메모리에서 읽기 / 쓰기하기 때문에 발생했으며 char c; 를 쓰려고 할 때 분명합니다 char c; 메모리에있는 1 바이트는 완전한 8 바이트 (즉, 단어)를 가져 와서 그것의 첫 번째 바이트 만 소비하며 그 7 연속 바이트는 비어있어 구조체 패딩에 대한 읽기 및 쓰기 작업에 액세스 할 수 없습니다.

구조용 패킹

그러나 packed 속성을 추가하면 컴파일러에서 패딩을 추가하지 않습니다.

struct __attribute__((__packed__)) foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

이제 sizeof(struct foo)17 을 반환합니다.

일반적으로 패킹 된 구조가 사용됩니다.

  • 공간 절약.
  • 네트워크의 각 노드의 각 아키텍처 정렬에 의존하지 않고 네트워크를 통해 전송할 데이터 구조를 포맷합니다.

ARM Cortex-M0와 같은 일부 프로세서는 정렬되지 않은 메모리 액세스를 허용하지 않는다는 점을 고려해야한다. 이 경우 구조체 패킹은 정의되지 않은 동작일으키고 CPU를 손상시킬 수 있습니다.

구조 패딩

struct 가 32 비트 컴파일러로 정의되고 컴파일 struct 가정 해보자.

struct test_32 {
    int a;      // 4 byte
    short b;    // 2 byte
    int c;      // 4 byte    
} str_32;

struct 는 단지 10 바이트의 메모리를 차지할 것으로 예상되지만, sizeof(str_32) 를 인쇄하면 12 바이트가 사용됩니다.

컴파일러가 빠른 액세스를 위해 변수를 정렬하기 때문에 이런 일이 발생했습니다. 공통 패턴은 기본 유형이 N 바이트를 차지할 때 (N은 1, 2, 4, 8, 16과 같이 2의 거듭 제곱이며 드물게 더 크지 않음) 변수는 N 바이트 경계에 정렬되어야합니다 N 바이트의 배수).

sizeof(int) == 4sizeof(short) == 2 표시된 구조의 경우 일반적인 레이아웃은 다음과 같습니다.

  • int a; 오프셋 0에 저장; 크기 4.
  • short b; 오프셋 4에 저장; 크기 2.
  • 오프셋 6에서 이름이없는 패딩; 크기 2.
  • int c; 오프셋 8에 저장; 크기 4.

따라서 struct test_32 는 12 바이트의 메모리를 차지합니다. 이 예제에서는 뒤쪽 패딩이 없습니다.

컴파일러는 struct test_32 내의 멤버가 빠르게 액세스 할 수 있도록 4 바이트 경계에서 시작하여 모든 struct test_32 변수가 저장되도록합니다. 반환 된 포인터가 모든 데이터 유형과 함께 사용하기에 충분히 정렬되도록하려면 malloc() , calloc()realloc() calloc() 과 같은 메모리 할당 함수가 필요하므로 동적으로 할당 된 구조도 올바르게 정렬됩니다.

32 비트 모드에서 컴파일 할 때, 컴파일러가와 장소, - (맥 맥 OS 시에라 또는 Mac OS X 실행 예를 들어, 인텔 코어 i7은) 당신은 64 비트 인텔 x86_64의 프로세서에 같은 이상한 상황을 끝낼 수있는 double A의 정렬 4 바이트 경계; 그러나 동일한 하드웨어에서 64 비트 모드로 컴파일 할 때 컴파일러는 8 바이트 경계에 double 정렬됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow