2012-07-01 30 views
9

GCC uygulanmasında bir hata:C11, aşağıdaki yapı çalışma bit alanları

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

bir _Bool, ardından 4 bit kullanıldığı bir unsigned (4 bayt) olarak GCC tarafından karşıladığı Gets the Toplam uzunluğu 8 bayt olan (1 bayt) 1 bit kullanılır.

C99 ve C11'in özellikle bir bit alanı üyesi olarak _Bool'a izin verdiğini unutmayın. C11 standart (ve muhtemelen C99 çok) da §6.7.2.1 'Yapısı ve sendika belirticilere' ¶11 altında şöyle denilmektedir:

bir uygulama biraz-alan sığabileceği büyüklükte herhangi adreslenebilir depolama birimi tahsis edebilir. Yeterli boşluk kalırsa, bir yapıdaki diğer bir bit alanını hemen takip eden bir bit alanı, aynı birimin bitişik bitlerine doldurulur.

Yani üyesi yukarıda b toplam büyüklüğü 4 byte bir yapı ile sonuçlanan üyesi a için ayrılan depolama birimine, içine paketlenmiş edilmiştir gerektiğine inanıyoruz.

GCC doğru davranır ve iki üyeleri için aynı türleri kullanılırken ambalaj meydana veya bir unsigned ve diğer signed, ama tipleri unsigned ve _Bool bunları işlemek için GCC tarafından çok farklı sayılabilir görünmektedir zaman doğru şekilde.

Birisi standardı yorumlamamı onaylayabilir mi ve bu gerçekten bir GCC hatası mı?

Ayrıca bir çalışma ile ilgileniyorum (bazı derleyici anahtarı, pragma, __attribute__ ...).

Ben -std=c11 gcc'den 4.7.0 kullanıyorum (diğer ayarlar aynı davranışı gösterir rağmen.)

+0

GCC uzantısının '__attribute__ (paketlenmiş)) buradaki üyelere uygulanabileceğini unutmayın. ancak bu problemin ortogonalidir (4 + 1 = 5 boyutunda bir yapıya, yani aynı sorunla sonuçlanır.) – ndkrempel

+0

İlgili: http://stackoverflow.com/questions/308364/c-bitfield-packing-with -boşluklar (ama C++, bit-alanları üzerinde kendi ifadesinde tam olarak yorucu değildir.) – ndkrempel

+0

Yukarıda bağlantılı soruya verilen bir cevaba göre, bu davranış gcc 4.2.4'te oluşmamıştır. o zamandan beri bir gerileme. – ndkrempel

cevap

10

açıklanan davranışı C99 ve C11 standartlarına uygun değildir, ancak MSVC derleyici ile ikili uyumluluk için sağlanır (olağandışı yapı ambalaj davranışı olan.)

Neyse ki, ya komut satırı anahtarı -mno-ms-bitfields (documentation bakınız) ile yapı uygulanan __attribute__((gcc_struct)) ile kodunda ya devre dışı bırakılabilir. Kullanılması

+0

Bu, herhangi bir yerde belgelenmiş mi? 'Mno-ms-bitfields' –

+0

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

+0

için yararlı bir şey bulamıyorum. Bunu daha önce bulamadım. Yorumların uzun vadeli olması gerekmediğinden, cevabınızı düzenlemenize yardımcı olur. –

0

hem GCC 4.7.1 64-bit derleme ile (ev yapımı) ve Mac OS X 10.7.4 üzerinde GCC 4.2.1 (LLVM/clang †), bu kod verimleri -std=c99 modunda 4:

#include <stdio.h> 

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

Windows'da bildirdiğiniz boyutun yarısı budur. Bana göre şaşırtıcı derecede büyük gözüküyor (1 byte büyüklüğünde olmasını beklerim), ancak platformun kuralları ne olduklarıdır. Temel olarak, derleyici, istediğiniz kuralları takip etmek zorunda değildir; Çalıştırıldığı platformun kurallarına uygun olabilir ve şansın olduğu yerde, üzerinde çalıştığı platformun kurallarını bile belirleyebilir.(Bu son yazılmıştır u.iu.s sonra kere), ama alan a 4 en az önemli bit içinde depolanan olduğunu gösterir ve saha b sonraki bit saklanır

Bu, aşağıdaki programı hafif şüpheli davranışı vardır:

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

Çıktı: i686-elma-darwin11-LLV †

4 
4 
0x00000015 
0x0000001C 

m-gcc-4.2 (GCC) 4.2.1 (Apple Inc. build 5658) (LLVM build 2336.9.00)