2010-11-21 38 views
11

Ngày nay, với sự ngạc nhiên lớn của tôi, tôi phát hiện ra rằngC/C++ nhận được kích thước struct

Khi các nhà điều hành sizeof được áp dụng cho một lớp, struct, hoặc loại công đoàn, kết quả là số byte trong một đối tượng thuộc loại đó, cộng với bất kỳ phần đệm nào được thêm vào để căn chỉnh các thành viên trên các ranh giới từ. Kết quả không nhất thiết phải tương ứng với kích thước được tính bằng cách thêm các yêu cầu lưu trữ của từng thành viên.

Tôi không biết về nó, và khá chắc chắn điều này là vi phạm một số mã cũ của tôi: để đọc tập tin nhị phân Tôi đã từng có cấu trúc như thế này một:

struct Header 
{ 
    union { 
     char identc[4]; 
     uint32 ident; 
    }; 
    uint16 version; 
}; 

và đọc những 6 byte trực tiếp với fread do sizeof:

fread(&header, sizeof(header), 1, f); 

Nhưng bây giờ sizeof(header) lợi nhuận 8!


Có thể rằng với các phiên bản GCC cũ sizeof(header) trở 6, hoặc tôi tâm trí của tôi là hoàn toàn biến mất?

Dù sao có bất kỳ toán tử nào khác (hoặc chỉ thị tiền xử lý hoặc bất kỳ thứ gì) cho phép trình biên dịch biết các cấu trúc lớn như thế nào - không bao gồm đệm?

Nếu không, cách nào sẽ là cách sạch để đọc cấu trúc dữ liệu thô từ tệp không yêu cầu viết quá nhiều mã?


EDIT: Tôi biết rằng đây không phải là cách đúng để đọc/ghi dữ liệu nhị phân: Tôi muốn có kết quả khác nhau tùy thuộc vào máy endianess và các công cụ. Dù sao phương pháp này là phương pháp nhanh nhất, tôi vẫn cố gắng đọc một số dữ liệu nhị phân để nhanh chóng lấy nội dung của nó, chứ không phải viết một ứng dụng tốt mà tôi sẽ sử dụng trong tương lai hoặc để phát hành.

+1

có thể trùng lặp của [Tại sao không phải là sizeof cho một cấu trúc bằng tổng của sizeof của mỗi thành viên?] (Http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct -equal-to-the-sum-of-sizeof-of-each-member) – cdhowie

+0

chỉ là một chú thích: standard-C cũng không cho phép các thành viên 'union' chưa được đặt tên; Ngoài ra, các loại tiêu chuẩn có kích thước cố định (được khai báo trong 'stdint.h') được gọi là' uint32_t' và 'uint16_t' – Christoph

+0

Sẽ hữu ích khi trích dẫn báo giá của bạn đến từ đâu. Đây có phải là tiêu chuẩn gần đây không? – beldaz

Trả lời

9

Điều bạn muốn là lệnh #pragma pack. Điều này cho phép bạn đặt bao bì thành bất kỳ số tiền nào bạn muốn. Thông thường, bạn sẽ đặt giá trị đóng gói thành 1 (hoặc là 0?) Trước định nghĩa cấu trúc của bạn và sau đó trả về giá trị mặc định sau định nghĩa.

Lưu ý rằng điều này không làm bất cứ điều gì để đảm bảo tính di động giữa các hệ thống.

Xem thêm: use-of-pragma-in-c và nhiều câu hỏi khác về SO

+0

Đây chính xác là những gì tôi cần. Cảm ơn bạn. – peoro

+0

Câu trả lời này nên đề cập rằng đó là Wintel cụ thể. –

+0

@R ..: thực sự nó đang làm việc với GCC trên Linux (có, tôi đã thử nghiệm trên kiến ​​trúc x86, nhưng tôi không thể thấy tại sao nó không hoạt động với GCC trên bất kỳ nền tảng nào khác). – peoro

3

Có mã bạn trình bày không phải là di động. Không chỉ kích thước cấu trúc mà còn các đơn đặt hàng byte có thể khác nhau.

1

Hầu hết các biên dịch cung cấp cho một phần mở rộng cụ thể cho phép bạn kiểm soát việc đóng gói các cấu trúc. Điều này sẽ cho phép bạn kiểm soát nó. Tuy nhiên, khi bạn viết cấu trúc trong nhị phân, bạn sẽ có thể chỉ cần viết nó và đọc nó bất kể đóng gói, như khi bạn viết cấu trúc, nó cũng nên viết sizeof (struct) byte. Trường hợp duy nhất mà điều này sẽ là một rắc rối là nếu bạn muốn đọc các tập tin được tạo bằng các phiên bản trước đó. Ngoài ra, bạn cần cân nhắc các vấn đề về thứ tự byte, v.v.

+0

Tôi không tạo dữ liệu nhị phân theo cùng một cách. Đó là một tập tin tôi cần để phân tích nhanh chóng. – peoro

1

Câu hỏi của bạn là trình biên dịch cụ thể, nhưng nói chung là nếu bạn xây dựng cấu trúc của bạn như vậy mà mỗi thành viên nằm trên một ranh giới có cùng kích thước như bản thân (bốn yếu tố byte trên ranh giới chia hết cho bốn, v.v.), bạn sẽ nhận được hành vi mà bạn muốn. Cũng theo dõi các trường hợp giống như trường hợp bạn trình bày khi phần đệm xuất hiện ở cuối cấu trúc để căn chỉnh phần đầu của phần tử đầu tiên của cấu trúc tiếp theo - nếu chúng được sắp xếp trong một mảng.

1

Có vẻ như bạn đã không hỏi một câu hỏi vì vậy tôi không chắc tại sao tôi thậm chí cố gắng trả lời! Nhưng có, đóng gói là quan trọng và sẽ thay đổi tùy thuộc vào phiên bản trình biên dịch, cờ, pragmas kiến ​​trúc mục tiêu, hướng gió, giai đoạn của mặt trăng và có khả năng nhiều thứ khác. Dumping nhị phân vào một tập tin (hoặc ổ cắm) không phải là một cách rất tốt của serializing bất cứ điều gì.

+0

Vâng câu hỏi chính, ngoài những nghi ngờ về padding, là: "Nếu không thì sẽ là một cách để đọc một cấu trúc dữ liệu thô từ một tập tin mà không cần phải viết quá nhiều mã?" – peoro

0

Có, vấn đề căn chỉnh. Đó là lý do tại sao các thông báo giao thức internet có các cấu trúc liên kết sao cho vấn đề này có thể tránh được khi gửi dữ liệu qua mạng.

Điều bạn có thể làm là sửa chữa cấu trúc của bạn để chúng được căn chỉnh đúng cách hoặc có các chức năng sắp xếp gọn gàng mà bạn sử dụng khi lưu và truy xuất dữ liệu.

1

Phần đệm thừa này là cần thiết để các thành viên được căn chỉnh đúng cách khi bạn tạo một mảng các cấu trúc này. Nếu không có nó, phần tử thứ 2 của mảng sẽ có thành viên ident được căn chỉnh trên một địa chỉ không phải là bội số của số 4.

Có thể đã quá muộn để làm bất cứ điều gì về nó, bạn có thể đã viết tệp với cấu trúc này trước đây . Thay đổi việc đóng gói sẽ làm cho các tệp này không đọc được. Tuy nhiên, có, có dữ liệu tập tin đó là phụ thuộc vào cài đặt trình biên dịch không phải là ý tưởng lớn nhất. Có những dữ liệu được lưu trữ trong một định dạng có thể đọc được là phổ biến trong những ngày này. Cả byte đĩa và chu kỳ CPU đều không đáng giá.

+0

Tôi không tạo dữ liệu nhị phân theo cùng một cách. Đó là một tập tin tôi cần để phân tích nhanh chóng. – peoro

+0

Vâng, bạn về mặt kỹ thuật cần phải tìm hiểu những gì đóng gói đã được sử dụng trong bất cứ chương trình đã viết dữ liệu. Bạn sẽ biết khi nào bạn cần tìm hiểu, bạn sẽ nhận được các giá trị rác. Thông thường từ bất kỳ dữ liệu nào được viết sau cấu trúc đó. –

2

Đây không phải là cách chính xác để xử lý tệp nhị phân. Ngoài các vấn đề liên kết, nó cũng có vấn đề về cuối. Cách thích hợp để đọc các tập tin nhị phân là với một mảng của uint8_t (hoặc unsigned char, nó thực sự không quan trọng) và các chức năng của riêng bạn để xây dựng một đại diện trong bộ nhớ ra khỏi dữ liệu.

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