Thứ Hai, 26 tháng 3, 2012

HƯỚNG DẪN KHAI BÁO STRUCT, UNION

Những định nghĩa , code mẫu trong bài viết này hoàn toàn có thể dùng được với những trình biên dịch ANSI-C. Đã kiểm tra trên Keil C và Hi-Tech C

Struct và Union được sử dụng rất nhiều trong lập trình C để định nghĩa kiểu dữ liệu người dùng, dễ dàng hơn trong các phép tính tra bảng, định dạng dữ liệu …

Hầu hết các trình biên dịch chuẩn ANSI-C đều có cách khai báo và sử dụng giống nhau. Bài viết này đề cập đến Struct và Union sử dụng cho 8051 và PIC với 2 trình biên dịch là Hi-Tech C và Keil C.

Struct
Một bài toán đơn giản khi tôi muốn truyền một Frame dữ liệu với cấu trúc bao gồm 6 byte:


[CMD:1byte][LEN:1byte][DATA:1byte], vậy muốn định nghĩa cái này một cách đơn giản dễ dùng thì định nghĩa Struct sẽ hiệu quả:











1struct DataPacket {










2    char CMD;










3    char LEN;










4    char DATA[4];










5};




Có thể hiểu ngay cách định nghĩa này, từ khóa struct, đến tên của Struct, sau đó khai báo lần lượt, 1 byte dự trữ cho CMD, với kiểu dữ liệu char, 1 byte dự trữ cho LEN với kiểu dữ liệu char, và 4 byte dự trự cho DATA với kiểu dữ liệu char. Chú ý, phần này chỉ khai báo cho trình biên dịch biết đây là kiểu dữ liệu DataPacket sẽ dùng trong chương trình.


Vậy dùng Struct này thế nào:











1struct DataPacket MyData;




Khai báo biến MyData có kiểu dữ liệu DataPacket, chú ý là phải có từ khóa struct đằng trước.
Cách sử dụng trong chương trình chính, truy xuất, gán dữ liệu cho MyData











1/* Gán dữ liệu cho MyData */










2    MyData.CMD = 0x01;










3    MyData.LEN = 0x02;










4    char i;










5    for(i=0;i<3;i++) {










6        MyData.DATA[i] = i*2;










7    }




Với kiểu struct này, trình biên dịch sẽ dành ra 6 byte để cấp phát cho MyData theo thứ tự
+-------+-------+---------+---------+---------+---------+
| CMD | LEN | DATA[0] | DATA[1] | DATA[2] | DATA[3] |
+-------+-------+---------+---------+---------+---------+

Ngoài ra còn có thể khải báo struct bằng từ khóa typedef










1typedef struct {










2    char CMD;










3    char LEN;










4    char DATA[4];










5} DataPacket;










6 










7DataPacket MyData1;










8DataPacket MyData2;




Với cách này, từ khóa typedef đặt trước struct, và tên của struct đặt sau block {}, lúc này trình dịch coi DataPacket như một kiểu dữ liệu được định nghĩa giống char, hay int

Union: cũng giống như struct, tuy nhiên, struct khai báo dữ liệu theo chiều dài, nghĩa là khai báo 1 phần từ trong struct sẽ cấp phát đúng bằng số byte mà phần tử đó cần (chẳng hạn ví dụ trên). Trong khi Union khai báo dữ liệu theo chiều dọc, nghĩa là tất cả các phần từ sẽ chỉ định nghĩa cho 1 vùng dữ liệu nào. Hãy xem ví dụ để hình dung thêm.
Yêu cầu ở đây, tôi muốn định nghĩa 2 byte dữ liệu, nhưng tôi muốn truy xuất nó bằng 2 tên.











1union WORD {










2    int WORD_VAL1;










3    int WORD_VAL2;










4};










5 










6union WORD MyVar;






Debug sử dụng Keil C - Code trên hoàn toàn có thể dùng với Hi-Tech C


Trình biên dịch cấp phát bộ nhớ cho kiêu Union như sau:
+-------+-------+
| BYTE1 | BYTE0 |
+---------------+
| WORD_VAL1 |
+---------------+
| WORD_VAL2 |
+---------------+

Cả WORD_VAL1 và WORD_VAL2 đều trỏ đến cùng 1 địa chỉ RAM

Giống như struct, còn một các khác để khai báo union










1typedef union  {










2    int WORD_VAL1;










3    int WORD_VAL2;










4}WORD;










5 










6WORD MyVar;




Kết hợp union và struct: Bằng cách kết hợp này, dữ liệu trở nên linh hoạt hơn, ngoài ra, có thể dễ dàng tách hay ghép nhiều Byte lại một cách nhanh chóng. Ví dụ:










1typedef union {










2    int WordVal;










3    struct {










4        char ByteLo;










5        char ByteHi;










6    }Bytes;










7}REG;




Sử dụng như sau










1REG x;










2x.WordVal = 0x1234;










3/* Kết quả










4 x.Bytes.ByteHi = 0x12










5 x.Bytes.ByteLo = 0x34










6*/




Ngoài ra, kết hợp union và struct còn có thể định nghĩa từng bit cho một thanh ghi (Cả KeilC và Hi-Tech C đều hỗ trợ):










01typedef union {










02    char ByteVal;










03    struct {










04        char bit0:1;










05        char bit1:1;










06        char bit2:1;










07        char bit3:1;










08        char bit4:1;










09        char bit5:1;










10        char bit6:1;










11        char bit7:1;










12    }Bits;










13    struct {










14        char NibbleLo:4;










15        char NibbleHi:4;










16    }Nibbles;










17    struct {










18        char used:5;










19        char unused:3;










20    }Other;










21BYTE;




Sử dụng:










01   BYTE y;










02y.ByteVal = 0x05;










03/*










04   see in watch #1










05   y.Bits.bit0 = 1;










06   y.Bits.bit1 = 0;










07   ....










08   y.Nibbles.NibbleLo = 0x05










09   y.Nibbles.NibbleHi = 0x00










10   ..










11*/




Kết quả

null

Kết quả Debug trên KeilC, hoàn toàn giống khi Debug dùng MPLAB cho Hi-TechC


//=============================================================

0 nhận xét:

Đăng nhận xét