Tuesday, August 28, 2012

We were busy developing the next version of the Kicad-tools utility when we came across this interesting piece of C Language tangle.
Essentially we wanted to have something like this.
Here the 'a' is1 Byte data and the 'dta' is a bit field made up in an Union.
typedef struct{
    BYTE a;
    union{
        struct{
            BYTE b0:1;
            BYTE b1:1;
            BYTE b2:1;
            BYTE b3:1;
            BYTE b4:1;
            BYTE b5:1;
            BYTE b6:1;
            BYTE b7:1;
        }bits;
        BYTE dta;
    }combi;
}ctyp;

This is the code snippet of the data structure.
We need to assign this data structure some constant values to hold the configuration bits.

However when we went ahead populating only a single value for Example:
ctyp ex2 = {4,{0x3A}};
This actually became:
     Patterns         =>{   a  ,{ dta  ,{ B7, B6, B5, B4, B3, B2, B1, B0}}
---------------------------------------------------------
            {4,{0x3A}}=>{ 0x04 ,{ 0x00 ,{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}
This was the main cause of one of the critical faliures in the software. We were found out that the assignement to a bit field union can only be done bit wise and not through the bigger members.
In this case the assignment can be done using 'combi.bits.bx' form but not directly to 'combi.dta'.
So when we give the pattern as:
ctyp ex3 = {4,{0,1,0,1,0,0,1,1}};
Then we get:
     Patterns         =>{   a  ,{ dta  ,{ B7, B6, B5, B4, B3, B2, B1, B0}}
---------------------------------------------------------
 {4,{0,1,0,1,0,0,1,1}}=>{ 0x04 ,{ 0xCA ,{ 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 }}

This were our findings. So we have the following rules for the Bit fields using unions in C:
  • When ever an constant assignment has to be done to the bit field using Unions it needs to be done to the bits alone and not to the bigger/complete data types.
  • The Constant assignment in the bit fields happens LSB first. [ We tested this in both VC++ compiler (VS2008 Express) and GCC 4.7 We saw the same results ]
Here is the program that we used to test this on the different compilers:
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#include <conio.h>
#endif
#ifndef BYTE
#define BYTE unsigned char
#endif
#if !defined(getch) && !defined(_getch)
#define getch() {char c;scanf("%c",&c);}
#endif
typedef struct{
    BYTE a;
    union{
        struct{
            BYTE b0:1;
            BYTE b1:1;
            BYTE b2:1;
            BYTE b3:1;
            BYTE b4:1;
            BYTE b5:1;
            BYTE b6:1;
            BYTE b7:1;
        }bits;
        BYTE dta;
    }combi;
}ctyp;

void printt(char * pattern,ctyp var)
{
    printf("\n %21s=>{ 0x%02X ,{ 0x%02X ,{ %01d , %01d , %01d , %01d , %01d , %01d , %01d , %01d }}",
        pattern,var.a,var.combi.dta,var.combi.bits.b7,var.combi.bits.b6,
        var.combi.bits.b5,var.combi.bits.b4,
        var.combi.bits.b3,var.combi.bits.b2,
        var.combi.bits.b1,var.combi.bits.b0);
}

void main()
{
    ctyp ex1 = {4,{5}};
    ctyp ex2 = {4,{0x3A}};
    ctyp ex3 = {4,{0,1,0,1,0,0,1,1}};
    ctyp ex4 = {4,{1,0,1,0,0,1,0,1}};
    printf("\n Union Testing Program\n");
    printf("\n     Patterns         =>{   a  ,{ dta  ,{ B7, B6, B5, B4, B3, B2, B1, B0}}");
    printf("\n---------------------------------------------------------");
    printt("{4,5}",ex1);
    printt("{4,{0x3A}}",ex2);
    printt("{4,{0,1,0,1,0,0,1,1}}",ex3);
    printt("{4,{1,0,1,0,0,1,0,1}}",ex4);
#ifdef WIN32
    _getch();
#else
    getch();
#endif
}

Hope that this insight would also help to decide on how to use the unions for bit fields and registers application in C.

{ 2 Discuss... read them below or Comment }

  1. Great work. I am highly obliged that you are sharing such info with us. I would appreciate if you will post on daily basis and that too with good typical info which i didn't get from anywhere. Being an C aspirant athttp://www.wiziq.com/course/5776-object-oriented-programming-with-c, I really appreciate your work

    ReplyDelete
  2. Hello,

    Just wanted to mention the C language specifies that only the _first_ union type can be initialized.

    See http://www.mers.byu.edu/docs/standardC/declare.html#Object Initializers

    So, if you move the "dta" byte in front of the bit declarations, then you can initialize with a byte value.

    The "oddness" you show, is because your second initializer is only initializing the first union type (in this case one bit).

    -Xark

    ReplyDelete

Welcome to Boseji's Blog

Popular Post

Blogger templates

Welcome

Creation by Electronics Hobbyists from Bharat(India) to encourage & help people. This blog hosts the numerous innovations, discoveries and projects we provide.
Our Research Wing Adhar Labs
Contact Form | Email Address
We Support Open Source Hardware Definition v1.0
Creative Commons License
All works on this blog are licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
Based on a work at forbharat.wordpress.com and m8051.blogspot.com.

Permissions beyond the scope of this license may be available at http://forbharat.wordpress.com/permissions/.
Thank you for all your support.

© A.D.H.A.R Labs Research 2008-2013 . Powered by Blogger.

Follow by Email

Followers

PCB Unit Converter

mils
mm

- Copyright © Electronics for Bharat -Robotic Notes- Powered by Blogger - Designed by Johanes Djogan -