Đúng nhưng...
Chắc chắn là có thể , nhưng nó thường là vô nghĩa (đối với bất kỳ chương trình nào không sử dụng hàng tỷ con số này):
#include <stdint.h> // don't want to rely on something like long long
struct bad_idea
{
uint64_t var : 40;
};
Ở đây, var
thực sự sẽ có chiều rộng 40 bit với chi phí tạo ra mã kém hiệu quả hơn nhiều (hóa ra là "nhiều" sai rất nhiều - chi phí đo được chỉ là 1-2%, xem thời gian bên dưới), và thường không có kết quả. Trừ khi bạn cần một giá trị 24 bit khác (hoặc một giá trị 8 và 16 bit) mà bạn muốn đóng gói vào cùng một cấu trúc, việc căn chỉnh sẽ mất đi bất cứ thứ gì bạn có thể đạt được.
Trong mọi trường hợp, trừ khi bạn có hàng tỷ trong số này, sự khác biệt hiệu quả về mức tiêu thụ bộ nhớ sẽ không đáng chú ý (nhưng mã bổ sung cần thiết để quản lý trường bit sẽ đáng chú ý!).
Lưu ý:
Trong thời gian trung bình, câu hỏi đã được cập nhật để phản ánh rằng thực sự cần hàng tỷ con số, vì vậy đây có thể là một điều khả thi để làm, giả sử rằng bạn thực hiện các biện pháp để không làm mất lợi ích do liên kết cấu trúc và đệm, tức là bằng cách lưu trữ thứ gì đó khác trong 24 bit còn lại hoặc bằng cách lưu trữ các giá trị 40 bit của bạn trong các cấu trúc của mỗi 8 hoặc bội số của chúng).
Tiết kiệm ba byte một tỷ lần là đáng giá vì nó sẽ yêu cầu ít trang bộ nhớ hơn đáng kể và do đó gây ra ít bộ nhớ cache và bỏ lỡ TLB hơn, và trên tất cả là lỗi trang (lỗi một trang có trọng lượng hàng chục triệu hướng dẫn).
Mặc dù đoạn mã trên không sử dụng 24 bit còn lại (nó chỉ thể hiện phần "sử dụng 40 bit"), nhưng điều gì đó tương tự như sau sẽ là cần thiết để thực sự làm cho cách tiếp cận hữu ích trong ý nghĩa bảo tồn bộ nhớ - giả sử rằng bạn thực sự có dữ liệu "hữu ích" khác để đưa vào các lỗ hổng:
struct using_gaps
{
uint64_t var : 40;
uint64_t useful_uint16 : 16;
uint64_t char_or_bool : 8;
};
Kích thước cấu trúc và sự liên kết sẽ bằng một số nguyên 64 bit, vì vậy sẽ không có gì lãng phí nếu bạn tạo một mảng gồm một tỷ cấu trúc như vậy (ngay cả khi không sử dụng các phần mở rộng dành riêng cho trình biên dịch). Nếu bạn không sử dụng giá trị 8-bit, bạn cũng có thể sử dụng giá trị 48-bit và 16-bit (mang lại lợi nhuận tràn lớn hơn).
Ngoài ra, bạn có thể, với chi phí khả dụng, đặt 8 giá trị 40 bit vào một cấu trúc (bội số chung nhất của 40 và 64 là 320 = 8 * 40). Tất nhiên sau đó mã của bạn mà truy cập các yếu tố trong mảng các cấu trúc sẽ trở thành nhiều phức tạp hơn (mặc dù một lẽ có thể thực hiện một operator[]
mà phục hồi các chức năng mảng tuyến tính và da mức độ phức tạp cấu trúc).
Cập nhật:
Đã viết một bộ thử nghiệm nhanh, chỉ để xem các trường bit (và quá tải toán tử với các tham chiếu trường bit) sẽ có gì. Đã đăng mã (do độ dài) tại gcc.godbolt.org , kết quả kiểm tra từ máy Win7-64 của tôi là:
Running test for array size = 1048576
what alloc seq(w) seq(r) rand(w) rand(r) free
-----------------------------------------------------------
uint32_t 0 2 1 35 35 1
uint64_t 0 3 3 35 35 1
bad40_t 0 5 3 35 35 1
packed40_t 0 7 4 48 49 1
Running test for array size = 16777216
what alloc seq(w) seq(r) rand(w) rand(r) free
-----------------------------------------------------------
uint32_t 0 38 14 560 555 8
uint64_t 0 81 22 565 554 17
bad40_t 0 85 25 565 561 16
packed40_t 0 151 75 765 774 16
Running test for array size = 134217728
what alloc seq(w) seq(r) rand(w) rand(r) free
-----------------------------------------------------------
uint32_t 0 312 100 4480 4441 65
uint64_t 0 648 172 4482 4490 130
bad40_t 0 682 193 4573 4492 130
packed40_t 0 1164 552 6181 6176 130
Những gì người ta có thể thấy là chi phí bổ sung của các trường bit là không thể bỏ qua, nhưng việc nạp chồng toán tử với tham chiếu trường bit như một điều tiện lợi là khá mạnh (tăng khoảng 3 lần) khi truy cập dữ liệu tuyến tính theo cách thân thiện với bộ nhớ cache. Mặt khác, khi truy cập ngẫu nhiên, nó hầu như không quan trọng.
Những định thời này cho thấy rằng chỉ cần sử dụng số nguyên 64 bit sẽ tốt hơn vì chúng vẫn nhanh hơn về tổng thể so với trường bit (mặc dù chạm vào nhiều bộ nhớ hơn), nhưng tất nhiên chúng không tính đến chi phí lỗi trang với bộ dữ liệu lớn hơn nhiều. Nó có thể trông rất khác khi bạn dùng hết RAM vật lý (tôi đã không kiểm tra điều đó).