Thread: Selecting bits with Unions.... Not working; please help!!

  1. #1
    Registered User
    Join Date
    Aug 2008
    Posts
    5

    Lightbulb Selecting bits with Unions.... Not working; please help!!

    Hi, I'm struggling with selecting bits using structures inside unions.

    I'm trying to convert an array of integers into a format suited to output on various chip pins.

    As it stands, I have 8 integers that I want to output to a number of demultiplexer ICs. Each IC requires a 3-bit input. These inputs need to come from a chip with 3 8-bit outputs. The problem therefore is that I need to convert these ints to 3-bit format, string them together to form a 24-bit long word, and then cut that word into 8-bit long chunks for output.

    This is what I've got so far, but as you can see, the bits don't seem to only partially reflect the correct values. Any idea what's wrong?

    http://sharebee.com/4c6bd1d8 <-- .c file

    Any help would be greatly appreciated!
    ======================================...
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    
    int short x;
    unsigned short led[8] = {1,1,1,1,1,1,1,1};
    
    
    // PRINTS INTEGER ARRAY
    printf("\nLed int array\n========================\n");
    for (x=0;x<=7;x++) printf("Led %d = %d\n",x,led[x]);
    printf("\n");
    
    // UNION OF 3-BIT NUMBERS AND INDIVIDUAL BITS
    union {
    struct mini_words //24 bytes?
    {
    unsigned short a:3;
    unsigned short b:3;
    unsigned short c:3;
    unsigned short d:3;
    unsigned short e:3;
    unsigned short f:3;
    unsigned short g:3;
    unsigned short h:3;
    } word;
    
    struct bytes
    {
    unsigned char b0:1;
    unsigned char b1:1;
    unsigned char b2:1;
    unsigned char b3:1;
    unsigned char b4:1;
    unsigned char b5:1;
    unsigned char b6:1;
    unsigned char b7:1;
    unsigned char b8:1;
    unsigned char b9:1;
    unsigned char b10:1;
    unsigned char b11:1;
    unsigned char b12:1;
    unsigned char b13:1;
    unsigned char b14:1;
    unsigned char b15:1;
    unsigned char b16:1;
    unsigned char b17:1;
    unsigned char b18:1;
    unsigned char b19:1;
    unsigned char b20:1;
    unsigned char b21:1;
    unsigned char b22:1;
    unsigned char b23:1;
    unsigned char b24:1;
    } b;
    } un;
    
    
    
    
    // FILLING STRUCTURE WITH DATA FROM ARRAY
    un.word.a=(led[0]);
    un.word.b=(led[1]);
    un.word.c=(led[2]);
    un.word.d=(led[3]);
    un.word.e=(led[4]);
    un.word.f=(led[5]);
    un.word.g=(led[6]);
    un.word.h=(led[7]);
    
    // PRINTING CURRENT STATE OF 3-BIT WORDS IN UNION
    printf("Assignments to structure\n========================\n");
    printf(" %hd ",un.word.a);
    printf("%hd ",un.word.b);
    printf("%hd ",un.word.c);
    printf("%hd ",un.word.d);
    printf("%hd ",un.word.e);
    printf("%hd ",un.word.f);
    printf("%hd ",un.word.g);
    printf("%hd\n\n",un.word.h);
    
    
    
    printf("Bits in string\n========================\n");
    printf("%d",un.b.b0);
    printf("%d",un.b.b1);
    printf("%d ",un.b.b2);
    printf("%d",un.b.b3);
    printf("%d",un.b.b4);
    printf("%d ",un.b.b5);
    printf("%d",un.b.b6);
    printf("%d",un.b.b7);
    printf("%d ",un.b.b8);
    printf("%d",un.b.b9);
    printf("%d",un.b.b10);
    printf("%d ",un.b.b11);
    printf("%d",un.b.b12);
    printf("%d",un.b.b13);
    printf("%d ",un.b.b14);
    printf("%d",un.b.b15);
    printf("%d",un.b.b16);
    printf("%d ",un.b.b17);
    printf("%d",un.b.b18);
    printf("%d",un.b.b19);
    printf("%d ",un.b.b20);
    printf("%d",un.b.b21);
    printf("%d",un.b.b22);
    printf("%d",un.b.b23);
    
    getch();
    
    return(0);
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Try printing out the size of your 'word' struct.
    My guess is that it isn't 3 (like you're expecting).

    > unsigned short e:3;
    > unsigned short f:3;
    Up to e, you've used 15 bits (bits 0 to 14).
    But it might be down to the implementation whether the first bit of f ends up in bit 15 (what you want), or bit 16 (the start of the next storage unit, and not what you want).

    Declaring them as "unsigned long" may (repeat MAY) give the compiler a clue to use a 32-bit underlying storage unit, but it's anyones guess as to whether it will work.

    http://c-faq.com/struct/bitfields.html
    If you're trying to map bits in hardware, then bit-fields are not the answer.
    Sooner or later, you'll come unstuck.

    Unfortunately, in this case, doing all the bit-bashing yourself is the only way of getting a consistent good answer.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    But this mapping can't work, can it? I mean 8 shorts (16 bytes) into 24 bytes like that... How would you set 3rd byte from a, b, c... exept using b member?
    EDIT: I may be wrong, but you define word.a as short, being long 3 bytes, but by using normal assignment (un.word.a=...), compiler will treat it as normal short so it will set only 2 bytes of word.a, 3rd you can access only with un.b.b2 or pointer (but it remains unset in this prog).
    Last edited by rasta_freak; 08-10-2008 at 02:28 PM.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It took me a few minutes to figure out what the problem was.
    3 bits don't make even sets of 16 bits. Unsigned short is a 16-bit integer. Since bitfields do not cross the natural boundary of their constituent base-type, when you have filled 15 bits, the next bit gets padded out.

    If you change your unsigned short to unsigned long [or "unsigned int" if you use a compiler which has 32-bit integers], then your results will be what I think you expect.

    Note: I took too long, Salem already answered it... ;-)

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    Can anyone please direct me to some docs where this syntax is explained? I've never used it. Like what exactly is the difference between short:3 & int:3 if they are all 3 bits?

  6. #6
    Registered User
    Join Date
    Aug 2008
    Posts
    5
    Salem, Matsp - Thanks for the replies guys... you've been a great help.

    Defining as long seems to fix it, athough based on what you've said, I'll have a stab at doing it the bit manipulation method instead.

    That is, unless you're think it'll work on GCC?

  7. #7
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by C99, section 6.7.2.1
    9 A bit-field is interpreted as a signed or unsigned integer type consisting of the specified
    number of bits.104) If the value 0 or 1 is stored into a nonzero-width bit-field of type
    _Bool, the value of the bit-field shall compare equal to the value stored.
    10 An implementation may allocate any addressable storage unit large enough to hold a bitfield.
    If enough space remains, a bit-field that immediately follows another bit-field in a
    structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
    whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
    implementation-defined. The order of allocation of bit-fields within a unit (high-order to
    low-order or low-order to high-order) is implementation-defined. The alignment of the
    addressable storage unit is unspecified.
    The difference between short:3 and int:3 being, where is the boundary, as that determines how many bitfields you can portably get inside one variable.

    Edit: Footnote 104 says that if you use plain int, you get signed or unsigned int at your compiler's discretion.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by rasta_freak View Post
    Can anyone please direct me to some docs where this syntax is explained? I've never used it. Like what exactly is the difference between short:3 & int:3 if they are all 3 bits?
    Here's one page that describes the syntax.
    http://www.cs.cf.ac.uk/Dave/C/node13.html

    Basicly, int x:3 is the same as short x:3 in all aspects except where short and int are differnet size and you have sufficinet sets of 3 bit values to go beyond the number of bits of a short.

    If we take the generic (C++ style) form:
    Code:
    T x:n;
    T y:n;
    then if bits in T is less than 2n, then they will be stored in the same T memory space. n must not be larger than the number of bits in T. So a char can only hold 8 bits [in commonl systems], an int can hold at least 16 bits in common systems and 32 bits in modern common systems. "long long int" could hold 64 bits.

    However, I should point out that there's no obligation to the compiler to actually store x and y in the above example in one T unit, even if T is more bits than 2n. It could just make two T size locations and store each field in one T unit each. The only guarantee is that the value stored will be masked to match the number of bits you have choosen.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    Salem, Matsp - - Thanks from me too
    EDIT: Ooops, meant Tabstop too..
    Last edited by rasta_freak; 08-10-2008 at 03:18 PM.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by dan56965 View Post
    Salem, Matsp - Thanks for the replies guys... you've been a great help.

    Defining as long seems to fix it, athough based on what you've said, I'll have a stab at doing it the bit manipulation method instead.

    That is, unless you're think it'll work on GCC?
    gcc should work OK with the "long" variety.

    Edit: If you are using gcc, then I would actually recommend using "int" instead of "long" - the reason being that if you ever switch to a system that uses 64-bit "long", you'd get unexpected changes versus a system where you have 32-bit "long" values.

    --
    Mats
    Last edited by matsp; 08-11-2008 at 04:12 AM.
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    Aug 2008
    Posts
    5
    Hey, just thought I'd add this for the sake of future searchers....

    I read about adding undeclared bits in a bit-field, to allow for limited container size.

    This now works for me without resorting to using long or int variables:

    Code:
          union {
                       struct byte_values
                       {
                              unsigned char b0:1;
                              unsigned char b1:1;
                              unsigned char b2:1;
                              unsigned char b3:1;
                              unsigned char b4:1;
                              unsigned char b5:1;
                              unsigned char b6:1;  
                              unsigned char b7:1;
                              unsigned char b8:1;
                              unsigned char b9:1;
                              unsigned char b10:1;
                              unsigned char b11:1;
                              unsigned char b12:1;
                              unsigned char b13:1;
                              unsigned char b14:1;
                              unsigned :1;        
                              unsigned char b15:1;
                              unsigned char b16:1;
                              unsigned char b17:1;
                              unsigned char b18:1;
                              unsigned :8;
                              unsigned char b19:1;
                              unsigned char b20:1;
                              unsigned char b21:1;
                              unsigned char b22:1;
                              unsigned char b23:1;          
                              unsigned char b24:1;
                              unsigned char b25:1;
                              unsigned char b26:1;
                              unsigned char b27:1;
                              unsigned char b28:1;
                              unsigned char b29:1;
                              unsigned char b30:1;
                              unsigned char b31:1;  
                              unsigned char b32:1;
    
     
                       } b;    
                
                       struct mini_words //24 bits?
                       {
                              unsigned short a:3;
                              unsigned short b:3;
                              unsigned short c:3;
                              unsigned short d:3;
                              unsigned short e:3;
                              unsigned short f:3;
                              unsigned short g:3;
                              unsigned short h:3;
                              unsigned int y_control:8;
                       } word;
    
                } un;
    Thanks again everyone.

  12. #12
    Registered User
    Join Date
    Aug 2008
    Posts
    5
    damn, posted the wrong thing there... it should have read like this:



    Code:
          union {
                       struct byte_values
                       {
                              unsigned char b0:1;
                              unsigned char b1:1;
                              unsigned char b2:1;
                              unsigned char b3:1;
                              unsigned char b4:1;
                              unsigned char b5:1;
                              unsigned char b6:1;  
                              unsigned char b7:1;
                              unsigned char b8:1;
                              unsigned char b9:1;
                              unsigned char b10:1;
                              unsigned char b11:1;
                              unsigned char b12:1;
                              unsigned char b13:1;
                              unsigned char b14:1;
                              unsigned :1;
                              unsigned char b15:1;
                              unsigned char b16:1;
                              unsigned char b17:1;
                              unsigned char b18:1;
                              unsigned char b19:1;
                              unsigned char b20:1;
                              unsigned char b21:1;
                              unsigned char b22:1;
                              unsigned char b23:1;          
                              unsigned :1;
                              unsigned char b24:1;
                              unsigned char b25:1;
                              unsigned char b26:1;
                              unsigned char b27:1;
                              unsigned char b28:1;
                              unsigned char b29:1;
                              unsigned char b30:1;
                              unsigned char b31:1;  
    
     
                       } b;    
                
                       struct mini_words //24 bits?
                       {
                              unsigned short a:3;
                              unsigned short b:3;
                              unsigned short c:3;
                              unsigned short d:3;
                              unsigned short e:3;
                              unsigned short f:3;
                              unsigned short g:3;
                              unsigned short h:3;    
                              unsigned int y_control:8;
                       } word;
                       
    
                } un;

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Saying
    unsigned short a:3;
    is no different to
    unsigned long a:3;
    it's still only 3 bits.

    > it should have read like this:
    Really?
    Because struct byte_values contains 34 bits.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bitwise Operators....
    By o0obruceleeo0o in forum C++ Programming
    Replies: 21
    Last Post: 04-09-2003, 06:45 AM
  2. what is the significance of low order and high order bits
    By Shadow12345 in forum Windows Programming
    Replies: 1
    Last Post: 11-16-2002, 11:46 AM
  3. copy some bits into a 8 bits binary number
    By Unregistered in forum C Programming
    Replies: 6
    Last Post: 05-29-2002, 10:54 AM
  4. opengl code not working
    By Unregistered in forum Windows Programming
    Replies: 4
    Last Post: 02-14-2002, 10:01 PM
  5. Help Please...bits
    By Unregistered in forum C Programming
    Replies: 11
    Last Post: 01-24-2002, 01:43 PM

Tags for this Thread