Neden bu yapı boyutu 2 yerine 3?


91

Bu yapıyı tanımladım:

typedef struct
{
    char A:3;
    char B:3;
    char C:3;
    char D:3;
    char E:3;
} col; 

sizeof(col)Bana 3 çıkışını vermek, ama bu 2 olmamalı? Sadece bir öğeyi yorumlarsam, sizeof2'dir. Nedenini anlamıyorum: 3 bitlik beş öğe 15 bite eşittir ve bu 2 bayttan azdır.

Bunun gibi bir yapıyı tanımlarken bir "iç boyut" var mı? Sadece bir açıklamaya ihtiyacım var çünkü şimdiye kadarki dil kavramımdan 3 değil 2 baytlık bir boyut bekliyordum.


4
Muhtemelen hizalamanın optimizasyonu. Bir sonraki bit boyutu gerçek kaplanan alana sığmazsa, yeni bir bayt başlatır.
πάντα ῥεῖ

4
Bazı harici kısıtlamalarınız yoksa ve platformunuz standartların sunduğu bazı ek garantiler sağlamadıkça, bit alanlarını kullanmanın pek bir anlamı yoktur.
David Rodríguez - dribeas

3
C için char kullanmanın int, stackoverflow.com/a/23987436/23118 kullanmaktan daha az taşınabilir olduğuna dikkat edin .
hlovdal

2
Bit alanları hakkında neredeyse her şeyin uygulama tanımlı olduğunu unutmayın. Farklı derleyicilerden farklı yanıtlar alabilirsiniz ve başvurulamaz. Ayrıca belirtmediğiniz için signed charveya unsigned charbelgelere bakmadan derleyicinin charbir bit alanında 'düz' mu işaretli mi yoksa imzasız mı olacağını söyleyemeyeceğinizi ve kararın (teoride) olup olmadığına ilişkin karardan farklı olabileceğini unutmayın. 'düz' char, bir bit alanının dışında kullanıldığında imzalı veya işaretsizdir.
Jonathan Leffler

3
Özellikle, C99, §6.7.2.1 Struct ve sendika belirteçleri ¶ 4. Bir bit alan nitelikli veya niteliksiz versiyonu bir tür olacaktır _Bool, signed int, unsigned intveya başka bir uygulama tanımlı türü. Bu charnedenle kullanımı, 'diğer uygulama tanımlı tür' kategorisine girer.
Jonathan Leffler

Yanıtlar:


95

charAlanlarınız için temel alınan tür olarak kullandığınızdan , derleyici bitleri bayta göre gruplandırmaya çalışır ve her bayta sekizden fazla bit koyamayacağı için bayt başına yalnızca iki alan depolayabilir.

Yapınızın kullandığı toplam bit toplamı 15'tir, bu nedenle bu kadar veriyi sığdırmak için ideal boyut bir short.

#include <stdio.h>

typedef struct
{
  char A:3;
  char B:3;
  char C:3;
  char D:3;
  char E:3;
} col; 


typedef struct {
  short A:3;
  short B:3;
  short C:3;
  short D:3;
  short E:3;
} col2; 


int main(){

  printf("size of col: %lu\n", sizeof(col));
  printf("size of col2: %lu\n", sizeof(col2));

}

Yukarıdaki kod (benimki gibi 64 bitlik bir platform 2için ) gerçekten ikinci yapı için verilecektir. A'dan daha büyük herhangi bir şey için short, yapı, kullanılan türün birden fazla öğesini doldurmayacaktır, bu nedenle - aynı platform için - yapı dört boyutta int, için sekiz long, vb.


1
Önerilen yapı tanımı hala yanlış. Doğru yapı tanımı 'işaretsiz kısa' kullanacaktır.
user3629249

21
@ user3629249 Neden işaretsiz kısa 'doğru'? Kullanıcı -4'ten 3'e kadar saklamak istiyorsa, kısa doğrudur. Kullanıcı 0'dan 7'ye kadar saklamak istiyorsa, işaretsiz kısa doğrudur. Orijinal soru işaretli bir tür kullanıyordu ancak bunun kasıtlı mı yoksa tesadüfi mi olduğunu anlayamıyorum.
Bruce Dawson

2
Neden fark var Beetween charve short?
GingerPlusPlus

5
@BruceDawson: Standart, uygulamaların charimzasız olmasına izin veriyor …
Thomas Eding

@ThomasEding True, standart karakterin işaretsiz olmasına izin veriyor. Ama asıl vurgulamak istediğim, işaretsiz kısa metnin doğru olduğunu iddia etmek için hiçbir neden gösterilmedi ( genellikle öyle olsa da).
Bruce Dawson

78

Minimum hizalama sınırını (1 bayt olan) kapsayan bir bit paket alanınız olamaz, bu nedenle muhtemelen şu şekilde paketlenirler:

byte 1
  A : 3
  B : 3
  padding : 2
byte 2
  C : 3
  D : 3
  padding : 2
byte 3
  E : 3
  padding : 5

(aynı bayt içindeki alan / doldurma sıraları kasıtlı değildir, sadece size fikir vermek içindir, çünkü derleyici onları nasıl tercih ettiğini belirleyebilir)


16

İlk iki bit alanı tek bir alana sığar char. Üçüncüsü buna uymaz charve yenisine ihtiyacı vardır. 3 + 3 + 3 = 9, 8 bitlik bir karaktere sığmaz.

Böylece ilk çift a alır char, ikinci çift a alır charve son bit alanı üçüncü bir alır char.


15

Derleyicilerin çoğu dolguyu kontrol etmenize izin verir, örneğin #pragmas kullanarak . İşte GCC 4.8.1 ile bir örnek:

#include <stdio.h>

typedef struct
{
    char A:3;
    char B:3;
    char C:3;
    char D:3;
    char E:3;
} col;

#pragma pack(push, 1)
typedef struct {
    char A:3;
    char B:3;
    char C:3;
    char D:3;
    char E:3;
} col2;
#pragma pack(pop)

int main(){
    printf("size of col: %lu\n", sizeof(col));  // 3
    printf("size of col2: %lu\n", sizeof(col2));  // 2
}

Derleyicinin varsayılan davranışının bir nedeni olduğunu ve muhtemelen size daha iyi performans sağlayacağını unutmayın.


9

ANSI C standardı, bit alanlarının "derleyicilerin bit alanlarını ancak uygun gördükleri halde paketlemelerine izin verilir" karşısında önemli bir avantaj sağlamak için nasıl paketlendiği hakkında çok az şey belirtmesine rağmen, yine de çoğu durumda derleyicilerin şeyleri en verimli şekilde paketlemesini yasaklar.

Özellikle, bir yapı bit alanları içeriyorsa, bir derleyicinin bunu bazı "normal" depolama tipinin bir veya daha fazla anonim alanını içeren bir yapı olarak saklaması ve daha sonra bu tür her alanı mantıksal olarak kurucu bit alanı parçalarına böler. Böylece verilen:

unsigned char foo1: 3;
unsigned char foo2: 3;
unsigned char foo3: 3;
unsigned char foo4: 3;
unsigned char foo5: 3;
unsigned char foo6: 3;
unsigned char foo7: 3;

Eğer unsigned char8 bit olduğunu, derleyici bu tür dört alanları tahsis ve (bir de olacağını tüm ama birine iki bitfields atamak için gerekli olacaktır char, kendi alanında). Tüm charbildirimler ile değiştirilmiş shortolsaydı short, biri beş bit alanını , diğeri kalan ikisini tutacak iki tür alanı olurdu.

Hizalama kısıtlamaları olmayan bir işlemcide veriler unsigned short, ilk beş alan unsigned chariçin ve son ikisi için üç baytta yedi üç bitlik alan saklanarak daha verimli bir şekilde düzenlenebilir . Üç baytta sekiz üç bitlik alan depolamak mümkün olsa da, bir derleyici buna yalnızca "dış alan" türü olarak kullanılabilecek üç baytlık bir sayısal tür varsa izin verebilir.

Kişisel olarak, bit alanlarının temelde faydasız olduğunu düşünüyorum. Kodun ikili olarak paketlenmiş verilerle çalışması gerekiyorsa, gerçek türlerin depolama konumlarını açıkça tanımlamalı ve ardından bunların bitlerine erişmek için makroları veya bu tür başka araçları kullanmalıdır. C'nin aşağıdaki gibi bir sözdizimini desteklemesi yararlı olacaktır:

unsigned short f1;
unsigned char f2;
union foo1 = f1:0.3;
union foo2 = f1:3.3;
union foo3 = f1:6.3;
union foo4 = f1:9.3;
union foo5 = f1:12.3;
union foo6 = f2:0.3;
union foo7 = f2:3.3;

Böyle bir sözdizimi, izin verilirse, kodun bit alanlarını kelime boyutlarına veya bayt sıralamalarına bakılmaksızın taşınabilir bir şekilde kullanmasını mümkün kılar (foo0, f1'in en az anlamlı üç bitinde olurdu, ancak bunlar alt veya daha yüksek adres). Ancak böyle bir özellik olmadığından, makrolar muhtemelen bu tür şeylerle çalışmanın tek taşınabilir yoludur.


2
Farklı derleyiciler, bit alanlarını farklı şekilde düzenler. Visual C ++ 'nın bununla alakalı olabileceğini nasıl yaptığına dair bazı belgeler yazdım. Can sıkıcı tehlikelerden bazılarına işaret ediyor: randomascii.wordpress.com/2010/06/06/…
Bruce Dawson

Normal bir türde deponun eşdeğerini söylüyorsunuz ve ilgilenilen tek değişkene ulaşmak için bit alanı operatörünü kullanın ve bu mekanizmayı basitleştirmek için bazı makrolar kullanın. C / c ++ 'da üretilen kodun da böyle bir şey yaptığını düşünüyorum. Bir yapı kullanmak, kodun "daha iyi" bir organizasyonu içindir, aslında hiç gerekli değildir.
Raffaello
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.