Tôi đã viết phiên bản nhị phân của iostream. Về cơ bản nó cho phép bạn viết các tệp nhị phân, nhưng cho phép bạn kiểm soát nhiều định dạng tệp. Ví dụ sử dụng: (. Nơi tiền tố là u16le)Phiên bản nhị phân của iostream
my_file << binary::u32le << my_int << binary::u16le << my_string;
Sẽ viết my_int như một số nguyên 32-bit unsigned, và my_string như là một chuỗi dài-tiền tố Để đọc các tập tin trở lại, bạn sẽ lật các mũi tên. Hoạt động tuyệt vời. Tuy nhiên, tôi đã va chạm vào thiết kế, và tôi vẫn đang ở trên hàng rào. Vì vậy, thời gian để hỏi SO. (Chúng tôi đưa ra một vài giả định, chẳng hạn như byte 8 bit, ints bổ sung 2 giây và IEEE nổi tại thời điểm này.)
iostreams, dưới mui xe, sử dụng streambufs. Đó là một thiết kế tuyệt vời thực sự - iostreams mã serialization của một 'int
' vào văn bản, và để cho streambuf cơ bản xử lý phần còn lại. Vì vậy, bạn nhận được cout, fstreams, stringstreams, vv Tất cả những điều này, cả iostreams và streambufs, được templated, thường là trên char, nhưng đôi khi cũng là một wchar. Tuy nhiên, dữ liệu của tôi là luồng byte, được thể hiện tốt nhất bởi 'unsigned char
'.
Lần thử đầu tiên của tôi là lấy mẫu các lớp dựa trên unsigned char
. std::basic_string
mẫu đủ tốt, nhưng streambuf
thì không. Tôi gặp phải một số vấn đề với một lớp học có tên là codecvt
, mà tôi không bao giờ có thể theo dõi chủ đề unsigned char
. Điều này đặt ra hai câu hỏi:
1) Tại sao một streambuf chịu trách nhiệm cho những thứ như vậy? Nó có vẻ như chuyển đổi mã nằm cách ra khỏi trách nhiệm của một streambuf - streambufs nên có một dòng, và dữ liệu đệm đến/từ nó. Chỉ có bấy nhiêu thôi. Một cái gì đó ở mức cao như chuyển đổi mã cảm thấy như nó nên thuộc về iostreams.
Vì tôi không thể lấy các streambuf hoạt động với char chưa ký, tôi đã quay trở lại char và chỉ truyền dữ liệu giữa char/unsigned char. Tôi đã cố gắng giảm thiểu số lượng phôi, vì lý do rõ ràng. Hầu hết các dữ liệu về cơ bản gió lên trong một hàm read() hoặc write(), sau đó gọi streambuf cơ bản. (Và sử dụng một diễn viên trong quá trình.) Chức năng đọc về cơ bản là:
size_t read(unsigned char *buffer, size_t size)
{
size_t ret;
ret = stream()->sgetn(reinterpret_cast<char *>(buffer), size);
// deal with ret for return size, eof, errors, etc.
...
}
Giải pháp tốt, giải pháp xấu?
Hai câu hỏi đầu tiên chỉ ra rằng cần thêm thông tin. Đầu tiên, các dự án như boost :: serialization được xem xét, nhưng chúng tồn tại ở mức cao hơn, ở chỗ chúng xác định định dạng nhị phân riêng của chúng. Điều này là nhiều hơn cho việc đọc/ghi ở mức độ thấp hơn, nơi mà nó muốn xác định định dạng, hoặc định dạng đã được xác định, hoặc siêu dữ liệu số lượng lớn là không cần thiết hoặc mong muốn.
Thứ hai, một số đã hỏi về công cụ sửa đổi binary::u32le
. Nó là một sự khởi đầu của một lớp có độ dài mong muốn và độ rộng mong muốn, tại thời điểm này, có lẽ đã được ký kết trong tương lai. Luồng giữ một bản sao của thể hiện được truyền cuối cùng của lớp đó và sử dụng nó trong tuần tự hóa. Đây là một chút của một workaround, tôi orginally cố gắng quá tải toán tử < < thusly:
bostream &operator << (uint8_t n);
bostream &operator << (uint16_t n);
bostream &operator << (uint32_t n);
bostream &operator << (uint64_t n);
Tuy nhiên vào thời điểm đó, điều này dường như không làm việc. Tôi đã gặp một số vấn đề với cuộc gọi hàm mơ hồ. Điều này đặc biệt đúng với các hằng số, mặc dù bạn có thể, như một poster được đề xuất, bỏ hoặc chỉ đơn thuần khai báo nó như là một const <type>
. Tôi dường như nhớ rằng có một số vấn đề lớn hơn tuy nhiên.
Sự cố gọi hàm mơ hồ của bạn có thể do thực tế rằng [u] int32_t thường được định nghĩa là "[unsigned] long". Vì vậy, nếu bạn cố gắng viết "[unsigned] int", mà chữ số có xu hướng, quảng cáo là cần thiết, nhưng loại để quảng bá là mơ hồ (ví dụ: dài so với gấp đôi). –
Bạn có thể xin vui lòng gửi đến đầu ra trình biên dịch trên những xung đột bạn đã có với unsigned char streambuf? – Basilevs