2010-02-21 38 views
7

Tôi có cấu trúc dữ liệu kế thừa dài 672 byte. Những cấu trúc được lưu trữ trong một tập tin, tuần tự, và tôi cần phải đọc chúng trongC++ liên kết cấu trúc và vectơ STL

Trong khi tôi có thể đọc chúng trong một-by-một, nó sẽ được tốt đẹp để làm điều này:.

// I know in advance how many structs to read in 
vector<MyStruct> bunchOfStructs; 
bunchOfStructs.resize(numberOfStructs); 

ifstream ifs; 
ifs.open("file.dat"); 
if (ifs) { 
    ifs.read(&bunchOfStructs[0], sizeof(MyStruct) * numberOfStructs); 
} 

này công trình, nhưng tôi nghĩ rằng nó chỉ hoạt động bởi vì kích thước cấu trúc dữ liệu xảy ra được chia đều bởi padding liên kết cấu trúc của trình biên dịch của tôi. Tôi nghi ngờ nó sẽ phá vỡ trên một trình biên dịch hoặc nền tảng.

Cách khác là sử dụng vòng lặp for để đọc từng cấu trúc một lần.

Câu hỏi -> Khi nào tôi phải lo ngại về căn chỉnh dữ liệu? Có động được cấp phát bộ nhớ trong một padding sử dụng vector hay không STL đảm bảo rằng các yếu tố là tiếp giáp?

+0

Các cấu trúc đó có được viết bằng tệp theo mã cũ hay bạn có kiểm soát được không? –

+0

Chúng được viết bằng mã kế thừa. Ngay cả khi tôi có thể thay đổi nó, tôi có thể phải đọc trong các tập tin được viết bởi các phiên bản cũ của ứng dụng. – Nate

Trả lời

4

Tiêu chuẩn yêu cầu bạn có thể tạo một mảng kiểu cấu trúc. Khi bạn làm như vậy, mảng được yêu cầu phải tiếp giáp. Điều đó có nghĩa, bất kỳ kích thước nào được phân bổ cho cấu trúc, nó phải là một cái cho phép bạn tạo một mảng của chúng. Để đảm bảo rằng, trình biên dịch có thể phân bổ thêm không gian bên trong cấu trúc, nhưng không thể yêu cầu thêm bất kỳ khoảng trắng nào giữa các cấu trúc.

Không gian cho dữ liệu trong một vector là (thường) được phân bổ với ::operator new (thông qua lớp Allocator) và ::operator new là bắt buộc để phân bổ không gian phù hợp để lưu trữ bất kỳ loại nào.

Bạn có thể cung cấp Allocator của riêng bạn và/hoặc quá tải ::operator new - nhưng nếu có, phiên bản của bạn vẫn được yêu cầu để đáp ứng các yêu cầu tương tự, vì vậy nó sẽ không thay đổi bất cứ điều gì về mặt này.

Nói cách khác, chính xác những gì bạn muốn là cần thiết để làm việc miễn là dữ liệu trong tệp được tạo theo cách cơ bản giống như cách bạn đang cố đọc lại. Nếu nó được tạo trên máy khác hoặc với một trình biên dịch khác (hoặc thậm chí là trình biên dịch tương tự với các cờ khác nhau) bạn có một số công bằng các vấn đề tiềm ẩn - bạn có thể nhận được sự khác biệt về tính cuối cùng, đệm trong cấu trúc, v.v.

Chỉnh sửa: Do bạn không biết liệu các cấu trúc đã được viết ra theo định dạng mà trình biên dịch mong đợi, bạn không chỉ cần đọc từng cấu trúc - bạn thực sự cần đọc các mục trong các cấu trúc tại một thời điểm, sau đó đặt từng mục vào một tạm thời struct và cuối cùng thêm phần đó vào số struct vào bộ sưu tập của bạn.

May mắn thay, bạn có thể quá tải operator>> để tự động hóa hầu hết việc này. Nó không cải thiện tốc độ (ví dụ), nhưng nó có thể giữ mã sạch của bạn:

struct whatever { 
    int x, y, z; 
    char stuff[672-3*sizeof(int)]; 

    friend std::istream &operator>>(std::istream &is, whatever &w) { 
     is >> w.x >> w.y >> w.z; 
     return is.read(w.stuff, sizeof(w.stuff); 
    } 
}; 

int main(int argc, char **argv) { 
    std::vector<whatever> data; 

    assert(argc>1); 

    std::ifstream infile(argv[1]); 

    std::copy(std::istream_iterator<whatever>(infile), 
       std::istream_iterator<whatever>(), 
       std::back_inserter(data)); 
    return 0; 
} 
+0

Hoàn hảo. Tôi biết rằng không có đệm giữa các cấu trúc trên đĩa, và không có đệm * bên trong * các cấu trúc trên đĩa. Nhưng tôi cho rằng tôi không có cách nào để biết liệu trình biên dịch có thêm đệm vào bên trong các cấu trúc trong bộ nhớ hay không. Vì vậy, có vẻ như tôi cần đọc mọi thứ trong một thời điểm để an toàn. – Nate

2

Đối với tệp hiện có của bạn, đặt cược tốt nhất của bạn là tìm ra định dạng tệp và đọc từng loại riêng lẻ, đọc và loại bỏ bất kỳ byte căn chỉnh nào.

Tốt nhất là không đưa ra bất kỳ giả định nào về căn chỉnh cấu trúc.

Để lưu dữ liệu mới vào tệp, bạn có thể sử dụng một cái gì đó như boost serialization.

+0

Nghe có vẻ như là cách an toàn. Chậm và tẻ nhạt, nhưng an toàn. :-) Tôi biết rằng không có đệm trong định dạng trên đĩa. – Nate

2

Trong trường hợp của bạn, bạn cần phải quan tâm về căn chỉnh bất cứ khi nào nó có thể thay đổi bố cục của cấu trúc của bạn. Có hai tùy chọn để làm cho mã của bạn dễ dàng hơn.

Đầu tiên, hầu hết các trình biên dịch đều có các thuộc tính mở rộng hoặc các chỉ thị tiền xử lý cho phép bạn đóng gói cấu trúc vào không gian tối thiểu. Tùy chọn này có khả năng sai lệch một số trường trong cấu trúc, điều này có thể làm giảm hiệu suất, nhưng sẽ đảm bảo rằng nó được đặt giống nhau trên bất kỳ máy nào bạn xây dựng nó. Kiểm tra trình biên dịch của bạn để tìm tài liệu về #pragma pack(). Trong GCC, bạn có thể sử dụng __attribute__((__packed__)).

Thứ hai, bạn có thể thêm phần đệm rõ ràng vào cấu trúc của mình. Tùy chọn này cho phép bạn duy trì các đặc tính hiệu suất của cấu trúc ban đầu, nhưng sẽ làm cho nó không rõ ràng về cách cấu trúc được đặt ra. Ví dụ:

struct s { 
    u_int8_t field1; 
    u_int8_t pad0[3]; 
    u_int16_t field2; 
    u_int8_t pad1[2]; 
    u_int32_t field3; 
}; 
1

Hơn căn chỉnh, bạn nên lo lắng về endianness. STL đảm bảo rằng lưu trữ trong một vector giống như một mảng, nhưng các trường số nguyên trong cấu trúc sẽ được lưu trữ ở các định dạng khác nhau giữa x86 và RISC.

Đối với điều chỉnh, Google cho #pragma pack(1).

0

Nếu bạn đang viết mã OO mà đòi hỏi sự hiểu biết về hoạt động bên trong của một lớp, bạn đang làm việc đó sai rồi. Bạn không nên giả định gì về các hoạt động bên trong của lớp; bạn chỉ nên giả định rằng các phương thức và thuộc tính hoạt động giống nhau trên bất kỳ nền tảng/trình biên dịch nào.

Có thể bạn nên thực hiện tốt hơn một lớp mô phỏng chức năng của vectơ (có lẽ bằng cách phân lớp vectơ). Hoạt động có lẽ là triển khai "mẫu proxy", nó chỉ có thể tải những cấu trúc đã được người gọi truy cập. Điều này sẽ cho phép bạn xử lý mọi vấn đề về cuối cùng cùng một lúc. Bằng cách này, nó sẽ làm cho nó hoạt động với bất kỳ nền tảng hoặc trình biên dịch nào.

Các vấn đề liên quan