2013-08-13 2 views
2

다음 코드는; s1 경우32 비트 구조의 구조체

struct s1 { 
    void *a; 
    char b[2]; 
    int c; 
}; 

struct s2 { 
    void *a; 
    char b[2]; 
    int c; 
}__attribute__((packed)); 

12 바이트의 크기를 갖는 s2 데이터는 4 개 바이트 청크로 읽을 및 }__attribute__((packed)); 단지 2 바이트 void*a;의 크기를 줄여 10 바이트의 크기는,이 때문 있는가?

다소 혼란 스럽지만 }__attribute__((packed));입니다. 그것은 인해 alignment, 컴파일러들이 시작 (성능) 최적의 주소를 확인하기 위해 필드 사이에 "쓰레기"숨겨진 추가합니다하는 과정이다

많은 감사

답변

5

.

을 사용하면 컴파일러가이를 수행하지 않도록합니다. 이는 하드웨어에 문제가있는 경우 구조에 액세스하는 것이 느려지거나 (예 : 버스 오류 등으로 인해 불가능할 수도 있음) 종종 의미합니다.

+0

하드웨어에 따라 충돌이 발생할 수도 있습니다. –

+0

@TomTanner도 물론. 고마워, 나는 편집했다. – unwind

0

이는 데이터 정렬과 데이터 패딩의 두 프로세스의 조합 인 data structure alignment이 원인입니다. 첫 번째 구조체는 말한대로 정렬되지만 두 번째 구조체는 압축되어 컴파일러가 구조체를 단어에 채우지 않도록합니다.

두 번째 구조는 문자 배열이 2 바이트이므로 이 아니고 void 포인터입니다 (모든 포인터가 그대로이므로 4 바이트로 유지됩니다). 이는 2 바이트 공간의 트레이드 오프가 (대부분의 환경에서) 하드웨어에 의해 손실 된 효율성에 가치가 없으므로 성능을 저해 할 수 있으며 정의되지 않은 동작을 초래할 수 있습니다.

+1

"모든 포인터가"상당히 쓸쓸하기 때문에 4 바이트로 남습니다. 나는 현재 포인터가 2 바이트와 4 바이트 인 C로 작업한다. 또한 8 바이트 포인터로 컴파일되었습니다. – chux

+0

@chux, 그 예를 보여줄 수 있습니까? 왜 이것이 일어날 지 궁금하다. –

+0

http://www.microchip.com/pagehandler/en-us/family/16bit/ 구형 DOS PC : 다양한 모드에는 16/32 데이터 포인터와 독립적으로 16/32 기능 포인터가 있습니다. Intel 64 비트 http://www.intel.com/content/www/us/en/architecture-and-technology/microarchitecture/intel-64-architecture-general.html – chux

2

Intel 프로세서에서 32 비트 정렬 데이터의 페치는 정렬되지 않은 것보다 상당히 빠릅니다. 다른 많은 프로세서에서 정렬되지 않은 페치는 불법 일 수도 있고,이거나 2 개의 명령어를 사용하여 시뮬레이션해야 할 수도 있습니다. 따라서 첫 번째 구조는 항상이 32 비트 구조의 c을 4로 나눌 수있는 바이트 주소로 정렬합니다. 그러나이 경우 저장소에 2 바이트가 낭비 될 것입니다. 한편

struct s1 { 
    void *a; 
    char b[2]; 
    int c; 
}; 

// Byte layout in memory (32-bit little-endian): 
// | a0 | a1 | a2 | a3 | b0 | b1 | NA | NA | c0 | c1 | c2 | c3 | 
// addresses increasing ====> 

때때로 당신은 절대적으로 C 구조로, (파일 형식, 또는 네트워크 패킷과 같은) 일부 정렬되지 않은 데이터 구조체를 매핑 할 필요가; 여기에 __attribute__((packed))을 사용하여 바이트를 채우지 않고 모든 것을 지정하도록 지정할 수 있습니다.

struct s2 { 
    void *a; 
    char b[2]; 
    int c; 
} __attribute__((packed)); 

// Byte layout in memory (32-bit little-endian): 
// | a0 | a1 | a2 | a3 | b0 | b1 | c0 | c1 | c2 | c3 | 
// addresses increasing ====>