Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

casting through different structures

Status
Not open for further replies.

stef88

MIS
Apr 27, 2007
13
GB
Hello!

I have a PACKED structure defined on 16 bytes and an array of unsigned char. It would be something like this:

#define ulong unsigned long

typedef struct partition{
ulong active:8;
CSH F;
ulong sysID:8;
CSH L;
ulong start;
ulong size;
}__attribute__((__packed__))partitie;

typedef struct CSH{
ulong H:8;
ulong C0:2;
ulong S:6;
ulong C:8;
}__attribute__((__packed__))CSH;

unsigned char v[16];

Now I do the following:

partiton *p;
p = v;

The problem is that it doesn't read all the fields as I was expected. It only reads well the active, sysID, size, start. It doesn't read well the CSH fields.
Although if O try to point an CSH pointer to the two bytes in v, were the respective data is stored, it's alright.

I must specify that i'm currently working in gcc, but I didn't find a dedicated forum for that on this site, and because Visual C++ is somehow related to C I think structures should behave the same in both programs.

Thank you!
 
> Although if O try to point an CSH pointer to the two bytes in v
CSH takes up 3 bytes (at least).

One thing you have no control over is the order of bits in a bit-field. Depending on your compiler, they may be packed L->R or R->L. Extracting bit information from an external data source using bit-fields is not portable.

Eg.
Code:
#include <stdio.h>

#define ulong unsigned long

typedef struct CSH{
    ulong H:8;
    ulong C0:2;
    ulong S:6;
    ulong C:8;
} __attribute__((__packed__)) CSH;

typedef struct partition{
    ulong active:8;
    CSH F;
    ulong sysID:8;
    CSH L;
    ulong start;
    ulong size;
} __attribute__((__packed__)) partitie;

void binary ( unsigned long a ) {
    unsigned long mask = 1<<31;
    int i;
    for ( i = 0 ; i < 32 ; i++, mask >>= 1 ) {
        putchar( a & mask ? '1' : '0' );
        if ( (i+1) % 4 == 0 ) putchar(' ');
    }
    putchar('\n');
}

int main ( ) {
    printf("%ld\n", sizeof(partitie) );
    printf("%ld\n", sizeof(CSH) );

    {
        union {
            CSH a;
            ulong b;
        } var;
        var.b = 0;
        var.a.H = ~0;
        printf("Bits for H: "); binary( var.b );
        var.b = 0;
        var.a.C0 = ~0;
        printf("Bits for C0:"); binary( var.b );
        var.b = 0;
        var.a.S = ~0;
        printf("Bits for S: "); binary( var.b );
        var.b = 0;
        var.a.C = ~0;
        printf("Bits for C: "); binary( var.b );
    }
    return 0;
}

$ gcc  foo.c
$ ./a.exe
16
3
Bits for H: 0000 0000 0000 0000 0000 0000 1111 1111
Bits for C0:0000 0000 0000 0000 0000 0011 0000 0000
Bits for S: 0000 0000 0000 0000 1111 1100 0000 0000
Bits for C: 0000 0000 1111 1111 0000 0000 0000 0000


> and because Visual C++ is somehow related to C
General C questions are asked here


--
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
 
Yes. I've made a mistake, I meant 3 bytes :)
I understand, I thought that maybe there is a way to make unions portable...

PS Thank you for the link
 
Unions are portable but bit packing isn't. Depends on the endianess of the machine you're running on.
 
Never use bit fields with packed data defined via external specifications. Use explicit shift/bit ops. It's a dirty job, but it works.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top