Cosmic UK Cosmic US Cosmic Germany Cosmic Italia Cosmic France


Cosmic Software Frequently Asked Questions


How are bitfileds allocated?


Bitfield allocation is an ANSI feature which is not normalized, and left open to the compiler implementation. By default, the Cosmic compiler fills bitfields from bit 0 (so the less signicant bit) up to bit 7 (for char bitfields), bit 15 (for int bitfields) or bit 31 (for long bitfields, when such a feature is supported). You can revert the fill order by compiling with option +rev, thus filling bitfields from the most significant bit (depending on the bitfield type) down to bit 0. Note that a new cell (whose size matches the bitfield base type) is created when a bitfield is larger than the available space in the current cell, or when the new bitfield has not the same base type than the previous one. With the following definition:
 
    union bb {
        char byte;
        struct b {
            char b0:1;
            char b1:1;
            char b2:1;
            char b3:1;
            char b4:1;
            char b5:1;
            char b6:1;
            char b7:1;
            } bit;
        } mem;
Using the default compiler behaviour, writing:
 
        mem.bit.b0 = 1;        is equivalent to     mem.byte |= 0x01;
Using the compiler with +rev option, writing:
 
        mem.bit.b0 = 1;        is equivalent to     mem.byte |= 0x80;
Now, if you are declaring a union between an array of 2 bytes and a bitfield structure, you may get different results depending on the base type for the bitfields and the +rev option. You can use either char bitfields or int bitfields, but the result will be different according to the filling rules described before:
 
   union bb2 { 
        char byte[2];
        struct b {
            char b0:1;        // bits b0 to b7 will overlay byte[0]
            char b1:1;
            char b2:1;
            char b3:1;
            char b4:1;
            char b5:1;
            char b6:1;
            char b7:1;
            char b10:1;     // bits b10 to b17 will overlay byte[1]
            char b11:1;
            char b12:1;
            char b13:1;
            char b14:1;
            char b15:1;
            char b16:1;
            char b17:1;
            } bit;
        } mem;
Using the +rev option will revert bits inside bytes, but b0-b7 stay in byte[0] and b10-b17 in byte[1]. The compiler is filling two char cells, so the +rev option reverts the bit filling order inside each cell, but not the cells themselves which are still allocated contiguously.
 
    mem.bit.b0 = 1;        is equivalent to    
    mem.byte[0] |= 0x01;    // by default
    mem.byte[0] |= 0x80;    // with +rev
Now with the following definition:
 
   union bb2 { 
        char byte[2];
        struct b {
            int b0:1;        // bits b0 to b7 will overlay byte[1] by default, and byte[0] with +rev
            int b1:1;
            int b2:1;
            int b3:1;
            int b4:1;
            int b5:1;
            int b6:1;
            int b7:1;
            int b10:1;     // bits b10 to b17 will overlay byte[0] by defautl, and byte[1] with +rev
            int b11:1;
            int b12:1;
            int b13:1;
            int b14:1;
            int b15:1;
            int b16:1;
            int b17:1;
            } bit;
        } mem;
The behaviour is different because the compiler is filling one int cell. The +rev option will revert the bits inside the cell thus reverting bits accross the 2 bytes.
 
    mem.bit.b0 = 1;        is equivalent to    
    mem.byte[1] |= 0x01;    // by default 
    mem.byte[0] |= 0x80;    // with +rev
Hopefully this will help you to find the proper declaration and option to match the display and syntax you want to implement. Note anyway that the ANSI standard clearly states that bitfields are *not* portables.