2012年6月7日 星期四

Bit-field in structures

參考網址
http://www.cs.cf.ac.uk/Dave/C/node13.html#SECTION001320000000000000000

Bit-field是C語言中比較低階的用法, 可以把一個structure中的bits做更細的切割來存取


比如以下的union / struct混合型

union {
    uint32_t packed;

    struct {
        uint8_t flag1: 1;
        uint8_t flag2: 1;
        uint8_t type:  4;
    } bits;
} x;

通常會使用到bit-field的場合:

  • 偷空間

  • 這應該是最主要的理由 某些structure member的值範圍不大, 就可以用bit-field的方式, 將一些member合併在一起

  • 特殊Header structure

  • 以IPv4 header為例 http://en.wikipedia.org/wiki/IPv4#Header
    可以用這樣的struct來存取
    typedef struct {
        uint8_t ver:  4;
        uint8_t ihl:  4;
        uint8_t dcsp: 6;
        uint8_t ecn:  2;
        uint16_t total;
        ...
    } ipv4_header_t;
    
    PS: 這是big endian的寫法!

  • 寫driver時

  • 週邊的control register中通常存取時會以byte/word為單位, 但為了省空間, 通常也是會把不同的控制register合併在同一個word中
    使用bit-field來寫就可以模擬成OOP的方式, 對programmer比較friendly
    以8051 TMOD register為例 http://www.8052.com/tuttimer.phtml
    可以用這樣的structe來存取
    typedef struct {
        uint8_t t0m0:  1;
        uint8_t t0m1:  1;
        uint8_t t0:    1;
        uint8_t gate0: 1;
        uint8_t t1m0:  1;
        uint8_t t1m1:  1;
        uint8_t t1:    1;
        uint8_t gate1: 1;
    } tmod_t;
    
    PS: 這是little endian的寫法!

  • Boolean flags

  • 其實也算是偷空間的一種
    通常程式中用的是Boolean flag, 也就是只有true/false兩種值, 但一個flag變數起碼會佔用1 byte的空間 利用bit-field可以合併不同的flag, 省下空間
    特別是函數中的local flags, 用這個技巧, 還能降低CPU register使用量, 提高效率
    例如:
    int func (int arg)
    {
        union {
            uint8_t packed;
            struct {
                uint8_t isArgValid: 1;
                uint8_t isError:    1;
                uint8_t isDone:     1;
            };
        } flags;
    
        flags.packed = 0;
        ...
        if (arg > 0)
            flags.isArgValid = 1;
        ...
        if (!flags.isArgValid)
            return 0;
        ...
        return 1;
    }
    

沒有留言:

張貼留言