Saya telah mendefinisikan struct ini:
typedef struct
{
char A:3;
char B:3;
char C:3;
char D:3;
char E:3;
} col;
The sizeof(col)
memberi saya output dari 3, tetapi tidak harus itu 2? Jika saya berkomentar hanya satu elemen, sizeof
adalah 2. Saya tidak mengerti mengapa: lima elemen 3 bit sama dengan 15 bit, dan itu kurang dari 2 byte.
Apakah ada "ukuran internal" dalam mendefinisikan struktur seperti ini? Saya hanya perlu klarifikasi, karena dari pengertian saya tentang bahasa selama ini, saya mengharapkan ukuran 2 byte, bukan 3.
signed char
atauunsigned char
, Anda tidak dapat mengetahui tanpa melihat dokumentasi apakah compiler akan memperlakukan 'biasa'char
di bidang bit sebagai bertanda tangan atau tidak, dan keputusannya bisa (secara teori) berbeda dari keputusan tentang apakah 'biasa'char
ditandatangani atau tidak bila digunakan di luar bidang bit._Bool
,signed int
,unsigned int
, atau beberapa jenis implementasi yang ditentukan lainnya. Menggunakanchar
karena itu jatuh ke dalam 'Jenis implementasi yang ditentukan' kategori.Jawaban:
Karena Anda menggunakan
char
tipe yang mendasari bidang Anda, kompilator mencoba mengelompokkan bit per byte, dan karena tidak dapat menempatkan lebih dari delapan bit dalam setiap byte, ia hanya dapat menyimpan dua bidang per byte.Jumlah total bit yang digunakan oleh struct Anda adalah 15, jadi ukuran yang ideal untuk memuat banyak data adalah a
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)); }
Kode di atas (untuk platform 64-bit seperti milik saya) memang akan menghasilkan
2
untuk struct kedua. Untuk sesuatu yang lebih besar dari ashort
, struct akan mengisi tidak lebih dari satu elemen dari tipe yang digunakan, jadi - untuk platform yang sama - struct akan berakhir dengan ukuran empat untukint
, delapan untuklong
, dll.sumber
char
danshort
?char
tidak ditandatangani…Karena Anda tidak dapat memiliki bidang paket bit yang membentang melintasi batas perataan minimum (yaitu 1 byte) sehingga mereka mungkin akan dikemas seperti
byte 1 A : 3 B : 3 padding : 2 byte 2 C : 3 D : 3 padding : 2 byte 3 E : 3 padding : 5
(perintah bidang / padding di dalam byte yang sama tidak disengaja, ini hanya untuk memberi Anda ide, karena kompilator dapat meletakkannya sesuai keinginannya)
sumber
Dua bidang bit pertama cocok menjadi satu
char
. Yang ketiga tidak bisa cocok dengan ituchar
dan membutuhkan yang baru. 3 + 3 + 3 = 9 yang tidak cocok dengan karakter 8 bit.Jadi pasangan pertama mengambil a
char
, pasangan kedua mengambil achar
, dan bidang bit terakhir mendapatkan yang ketigachar
.sumber
Kebanyakan kompiler memungkinkan Anda untuk mengontrol padding, misalnya menggunakan
#pragma
s . Berikut adalah contoh dengan GCC 4.8.1:#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 }
Perhatikan bahwa perilaku default kompilator ada karena suatu alasan dan mungkin akan memberi Anda kinerja yang lebih baik.
sumber
Meskipun standar ANSI C menentukan terlalu sedikit tentang bagaimana bitfields dikemas untuk menawarkan keuntungan yang signifikan atas "kompiler diizinkan untuk mengemas bitfields bagaimanapun mereka mau", namun dalam banyak kasus melarang kompiler untuk mengemas sesuatu dengan cara yang paling efisien.
Secara khusus, jika suatu struktur berisi bitfield, kompiler diperlukan untuk menyimpannya sebagai struktur yang berisi satu atau lebih kolom anonim dari beberapa jenis penyimpanan "normal" dan kemudian secara logis membagi setiap kolom tersebut menjadi bagian bitfield penyusunnya. Jadi, diberikan:
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;
Jika
unsigned char
8 bit, kompilator akan diminta untuk mengalokasikan empat bidang dari jenis itu, dan menetapkan dua bidang bit ke semua kecuali satu (yang akan berada dichar
bidangnya sendiri). Jika semuachar
deklarasi telah diganti denganshort
, maka akan ada dua field bertipeshort
, salah satunya akan menampung lima bitfield dan yang lainnya akan menampung dua sisanya.Pada prosesor tanpa batasan penyelarasan, data dapat disusun lebih efisien dengan menggunakan
unsigned short
untuk lima bidang pertama danunsigned char
untuk dua terakhir, menyimpan tujuh bidang tiga-bit dalam tiga byte. Meskipun dimungkinkan untuk menyimpan delapan bidang tiga-bit dalam tiga byte, kompilator hanya dapat mengizinkan itu jika ada tipe numerik tiga-byte yang dapat digunakan sebagai tipe "bidang luar".Secara pribadi, saya menganggap bitfields sebagaimana didefinisikan pada dasarnya tidak berguna. Jika kode perlu bekerja dengan data yang dikemas biner, kode harus secara eksplisit menentukan lokasi penyimpanan dari tipe aktual, dan kemudian menggunakan makro atau cara lain untuk mengakses bitnya. Akan sangat membantu jika C mendukung sintaks seperti:
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;
Sintaks seperti itu, jika diizinkan, akan memungkinkan kode untuk menggunakan bitfields secara portabel, tanpa memperhatikan ukuran kata atau urutan byte (foo0 akan berada di tiga bit paling signifikan dari f1, tetapi itu dapat disimpan di alamat yang lebih rendah atau lebih tinggi). Tidak adanya fitur seperti itu, bagaimanapun, makro mungkin satu-satunya cara portabel untuk beroperasi dengan hal-hal seperti itu.
sumber