2012-07-01 5 views
9

의 GCC 구현의 버그 :C11 다음 구조체의 작업 비트 필드

struct S { 
    unsigned a : 4; 
    _Bool b : 1; 
}; 

_Bool 다음, 4 비트가 사용되는지의 unsigned (4 바이트)로 GCC 의해 누워 얻는다 (4 바이트), 1 비트가 사용되며 총 크기는 8 바이트입니다.

C99 및 C11은 특별히 비트 필드 멤버로 _Bool을 허용합니다. C11 표준 (그리고 아마도 C99도)도 §6.7.2.1 '구조와 노동 조합 지정자'¶11에서 상태가 :

구현은 비트 필드를 보관 유지하는데 충분한 크기가 어떤 주소 저장 장치를 할당 할 수 있습니다. 충분한 공간이 남아있는 경우, 구조 내의 다른 비트 필드 바로 뒤에 오는 비트 필드는 동일한 유닛의 인접한 비트로 패킹되어야합니다.

그래서 부재는 상기 b 총 4 바이트 크기의 구조체 초래 부재 a에 할당 된 저장 부에 충전 된 것이 판단된다.

GCC가 제대로 작동하고 두 멤버에 대해 동일한 유형을 사용할 때 포장이 발생 않거나, 하나 unsigned 다른 signed,하지만 유형 unsigned_Bool는이를 처리하기 위해 GCC으로도 별개의 것으로 간주 것 같다 때 바르게.

누군가 내 표준 해석을 확인할 수 있습니까? 그리고 이것이 실제로 GCC 버그입니까?

나는 또한 work-around (일부 컴파일러 스위치, pragma, __attribute__ ...)에 관심이 있습니다.

내가 -std=c11와 GCC 4.7.0를 사용하고 있습니다 (다른 설정이 동일한 동작을 보여줍니다 있지만.)

+0

GCC 확장 '__attribute__ ((packed)'는 여기에있는 멤버들에게 적용될 수 있습니다. 이 문제와 직각을 이룹니다 (크기가 4 + 1 = 5 인 구조체, 즉 동일한 문제가 있음) – ndkrempel

+0

관련 : http://stackoverflow.com/questions/308364/c-bitfield-packing-with -bools (그러나 C++은 비트 필드에 대한 표현이 정확하지 않습니다.) – ndkrempel

+0

위의 질문에 대한 대답에 따르면이 동작은 gcc 4.2.4에서 발생하지 않았으므로 그 후 회귀. – ndkrempel

답변

10

기술 된 행동은 C99과 C11 표준과 호환되지 않습니다,하지만 MSVC 컴파일러와 바이너리 호환성을 위해 제공됩니다 (이상한 구조체 포장 동작을 가지고있다.)

은 다행히도, 또는 명령 줄 스위치 -mno-ms-bitfields합니다 (documentation 참조) 구조체에 적용 __attribute__((gcc_struct))와 코드 중 하나를 비활성화 할 수 있습니다. 사용

+0

어디에서 문서화되어 있습니까? 'mno-ms-bitfields'에서 유용한 것을 찾지 못했습니다. –

+0

https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#x86-Options – ndkrempel

+0

감사합니다. 전에는 그것을 발견하지 못했습니다. 주석은 장기적인 의미가 아니므로이를 편집하여 유용하게 사용할 수 있습니다. –

0

모두 GCC 4.7.1 64 비트 컴파일과 (조립식) 및 Mac OS X 10.7.4에 GCC 4.2.1 (LLVM/연타의 †)이 코드는 수율 -std=c99 모드에서 4 :

#include <stdio.h> 

int main(void) 
{ 
    struct S 
    { 
     unsigned a : 4; 
     _Bool b : 1; 
    }; 
    printf("%zu\n", sizeof(struct S)); 
    return 0; 
} 

Windows의 절반 크기입니다. 그것은 놀랍게도 커 보인다 (나는 1 바이트 크기가 될 것으로 기대한다). 그러나 플랫폼의 규칙은 그대로이다. 기본적으로 컴파일러는 원하는 규칙을 따르지 않아도됩니다. 그것이 실행되는 플랫폼의 규칙을 따를 수 있으며 기회가있는 곳에서 실행되는 플랫폼의 규칙을 정의 할 수도 있습니다.(가에 기록 최후 u.iu.s 후 액세스 때문에), 그러나 필드 a는 4 개의 최하위 비트에 저장되는 것을 도시하고 필드 b가 다음 비트에 저장된다

이 다음 프로그램 약간 모호한 문제를 가지고

#include <stdio.h> 

int main(void) 
{ 
    union 
    { 
     struct S 
     { 
      unsigned a : 4; 
      _Bool b : 1; 
     } s; 
     int i; 
    } u; 
    u.i = 0; 
    u.s.a = 5; 
    u.s.b = 1; 
    printf("%zu\n", sizeof(struct S)); 
    printf("%zu\n", sizeof(u)); 
    printf("0x%08X\n", u.i); 
    u.s.a = 0xC; 
    u.s.b = 1; 
    printf("0x%08X\n", u.i); 
    return 0; 
} 

출력 :는 i686-사과 darwin11 - LLV †

4 
4 
0x00000015 
0x0000001C 

(LLVM 빌드 2336.9.00)