C – Trường Bit (Bit Fields)

Giả sử chương trình C của bạn có nhiều biến TRUE/FALSE được nhóm theo cấu trúc (structure) được gọi là status như ví dụ sau.

struct {
   unsigned int widthValidated;
   unsigned int heightValidated;
} status;

Cấu trúc này cần các 8 byte trong không gian bộ nhớ. Nhưng thực ra, chúng ta sẽ lưu trữ giá trị 0 hoặc 1 trong mỗi biến. Do đó, ngôn ngữ lập trình C đưa ra một cách hay để tận dụng không gian bộ nhớ trong tình huống này.

Nếu bạn đang sử dụng các biến như vậy bên trong một cấu trúc thì bạn có thể xác định độ rộng của một biến để cho trình biên dịch C biết rằng bạn chỉ sử dụng số byte đó. Ví dụ, cấu trúc trên có thể được viết lại như sau:

struct {
   unsigned int widthValidated : 1;
   unsigned int heightValidated : 1;
} status;

Cấu trúc trên yêu cầu 4 byte không gian bộ nhớ cho biến status, nhưng chỉ có 2 bit được sử dụng để lưu các giá trị.

Nếu bạn định sử dụng tối đa 32 biến, mỗi biến có độ rộng là 1 bit, thì cấu trúc status cũng sẽ sử dụng 4 byte. Tuy nhiên, khi bạn có 33 biến, nó sẽ cấp phát sang vùng tiếp theo của bộ nhớ và nó sẽ bắt đầu sử dụng 8 byte. Chúng ta hãy kiểm tra ví dụ sau để hiểu khái niệm này.

#include <stdio.h>
#include <string.h>

/* define simple structure */
struct {
   unsigned int widthValidated;
   unsigned int heightValidated;
} status1;

/* define a structure with bit fields */
struct {
   unsigned int widthValidated : 1;
   unsigned int heightValidated : 1;
} status2;
 
int main( ) {
   printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
   printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
   return 0;
}

Kết quả in số byte dùng cho hai cấu trúc status1 và status2.

Memory size occupied by status1 : 8
Memory size occupied by status2 : 4

Khai báo Bit Field

Việc khai báo trường bit (bit field) có dạng như sau trong một cấu trúc (structure).

struct {
   type [member_name] : width ;
};
  • type : một kiểu số nguyên (integer type) để xác định giá trị một trường bit (bit field) được thông dịch. Kiểu có thể là int, signed int hoặc unsigned int.
  • member_name : tên của trường bit.
  • width : độ rộng – số bit trong một trường bit. Độ rộng này phải nhỏ hơn hoặc bằng độ rộng bit của kiểu (type).

Các biến được định nghĩa với độ rộng xác định trước được gọi là trường bit (bit field). Một trường bit có thể chứa nhiều hơn một bit; ví dụ: nếu bạn cần một biến để lưu trữ giá trị từ 0 đến 7, thì bạn có thể xác định một trường bit có độ rộng 3 bit như sau:

struct {
   unsigned int age : 3;
} Age;

Định nghĩa cấu trúc trên hướng dẫn trình biên dịch C rằng biến age sẽ chỉ sử dụng 3 bit để lưu trữ giá trị. Nếu bạn cố gắng sử dụng nhiều hơn 3 bit, thì nó sẽ không cho phép bạn làm như vậy. Hãy thử ví dụ sau.

#include <stdio.h>
#include <string.h>

struct {
   unsigned int age : 3;
} Age;

int main( ) {

   Age.age = 4;
   printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
   printf( "Age.age : %d\n", Age.age );

   Age.age = 7;
   printf( "Age.age : %d\n", Age.age );

   Age.age = 8;
   printf( "Age.age : %d\n", Age.age );

   return 0;
}

Khi đoạn code trên được biên dịch, nó sẽ biên dịch với một cảnh báo (warning) và khi được thực thi, nó sẽ tạo ra kết quả sau.

Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0

Ta thấy giá trị 8 đã không được in, thay vào đó là giá trị 0. Bởi vì giá trị 8 (nhị phân là 1000) cần 4 bit để lưu trữ, trong khi trường bit age chỉ có 3 bit nên chỉ có thể lưu giá trị 0 (nhị phân là 000)

(Tiếp theo)

Icons made by Freepik from www.flaticon.com