2015-03-20 30 views
6

Tôi cần phải tạo cấu trúc với bitfield để đóng gói một số dữ liệu đến từ phần cứng. Giả sử tôi sử dụng cơ chế biên dịch cụ thể để thực thi đóng gói và đặt hàng, là nó có thể để tạo ra một cấu trúc tương tự như sau (không đúng cú pháp):Bited lồng nhau trong C/C++

typedef struct _BYTE_OF_DATA 
{ 
    uint8_t Reserved1 : 2; 
    struct 
    { 
     uint8_t BitWithSomeMeaning : 1; 
     uint8_t BitWithSomeOtherMeaning : 1; 
    } BitsWithMeaning; 
    uint8_t Reserved2 : 4; 
} BYTE_OF_DATA, *PBYTE_OF_DATA; 

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size"); 

nào sau đó có thể được truy cập như sau:

BYTE_OF_DATA byteOfData; 

byteOfData.Reserved1 = 1; 
byteOfData.BitsWithMeaning.BitWithSomeOtherMeaning = 0; 

Lược đồ chính xác mà tôi đã mô tả ở trên sẽ không hoạt động, vì tôi đoán cấu trúc BitsWithMeaning cần phải bắt đầu tại một ranh giới byte. Tôi đã tự hỏi nếu có một số mẹo khác mà tôi có thể đạt được điều này "làm tổ" của bitfields.

+3

Macro có được phép không? Đây có phải là C++ hoặc C không? Tôi nghĩ rằng C + + bởi vì tôi không nghĩ rằng C có 'static_assert'. –

+0

Vì có một 'static_assert', tôi đoán nó phải là C++, vì vậy thẻ C có lẽ nên được loại bỏ. –

+2

C có 'static_assert' từ C11. Và câu hỏi cũng có thể có liên quan với C. – Morwenn

Trả lời

6

Để xây dựng trên nhận xét trước đó của tôi, điều gì đó dọc theo các dòng này sẽ cho phép kiểu truy cập bạn mong muốn. Mặc dù cách xa thanh lịch:

typedef union _BYTE_OF_DATA { 
    struct { 
     uint8_t Reserved1 : 2; 
     uint8_t : 2; 
     uint8_t Reserved2 : 4; 
    }; 
    struct { 
     uint8_t : 2; 
     uint8_t BitWithSomeMeaning : 1; 
     uint8_t BitWithSomeOtherMeaning : 1; 
     uint8_t : 4; 
    } BitsWithMeaning; 
} BYTE_OF_DATA, *PBYTE_OF_DATA; 

Cá nhân tôi rất thích mặt nạ và vị trí mặt nạ truyền thống và mang sổ đăng ký theo cách thủ công. Kinh nghiệm của tôi là việc truy cập bitfield I/O dễ bay hơi theo phong cách này luôn dẫn đến mã không hiệu quả và dễ bị đua.

+0

Được thăng hạng, vì điều này thực sự đạt được loại quyền truy cập mà tôi muốn thực hiện. Tuy nhiên, như bạn đã đề cập, điều này làm cho cấu trúc không thể đọc được; nó không phải là ngay lập tức rõ ràng những gì cấu trúc của sổ đăng ký là. – TripShock

+0

Định danh '_BYTE_OF_DATA' được dành riêng cho việc triển khai (trong cả C và C++). Trong C++ bạn thậm chí sẽ không bận tâm với 'typedef'. – MSalters

+0

@MSalters: Việc đặt tên đã được chuyển từ câu hỏi gốc và trong mọi trường hợp, có một cơ hội tốt cho việc triển khai này. Các loại định nghĩa đăng ký I/O này thường gặp nhất như là một phần của tiêu đề thiết bị của trình biên dịch C/C++ được nhúng. – doynax

1

Bạn nên sử dụng một công đoàn trong trường hợp này

typedef union _BYTE_OF_DATA { 
    uint8_t data; 
    struct { 
     uint8_t padding1 : 2; 
     uint8_t BitWithSomeMeaning : 1; 
     uint8_t BitWithSomeOtherMeaning : 1; 
     uint8_t padding 2 : 4; 
    } BitsWithMeaning; 
} BYTE_OF_DATA, *PBYTE_OF_DATA; 

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size"); 

Vì vậy, bạn có thể điền dữ liệu trong một shot:

BYTE_OF_DATA myByte; 

myByte.data = someotherbyte; 

Và có được chút với ý nghĩa:

int meaning1 = myByte.BitWithSomeMeaning; 
int meaning2 = myByte.BitWithSomeOtherMeaning; 

Hoặc làm đối diện:

myByte.data = 0; // Put all fields to 0 

myByte.BitWithSomeMeaning = 1; 
myByte.BitWithSomeOtherMeaning = 0; 

int data = myByte.data; 
0

Trong C++, các giải pháp đơn giản nhất có thể

struct BYTE_OF_DATA 
{ 
    uint8_t bits; 
    private: 
    struct 
    { 
     bool getBitWithSomeMeaning() const { return bool(bits&0x20); } 
     bool getWithSomeOtherMeaning() const { return bool(bits&0x10); } 
     void setBitWithSomeMeaning(bool b); 
     void setWithSomeOtherMeaning(bool b); 
    } BitsWithMeaning; 
}; 

Không getters/setters cho các lĩnh vực dành riêng rõ ràng. Ctor có lẽ nên đặt các trường đó thành 0 hoặc 1, như giao thức xác định.