tags:

views:

112

answers:

3

I have a c pointer to a structre type called uchar4 which looks like

{
    uchar x; 
    uchar y; 
    uchar z; 
    uchar w;
}

I also have data passed in as uint8*. I'd like to create a uchar* pointing to the data at the uint8* so I've tried doing this:

uint8 *data_in;
uchar4 *temp = (uchar4*)data_in;

However, the first 8 bytes always seem to be wrong. Is there another way of doing this?

EDIT:

the input data = 32 43 F6 A8 88 5A 30 8D 31 31 98 A2 E0 37 07 34

the output data = 32 88 31 E0 37 07 34 8D 31 31 98 A2 E0 37 07 34

The first half is always these seemingly random values

+1  A: 
  1. If sizeof(uint8) != sizeof(uchar4), then all bets are off.
  2. Do you realize that the bytes of an integer are not necessarily kept (in memory) in the order you expect?

Edited to add This example prints c3 d2 e1 f0. Does that answer your question?

#include <stdio.h>
typedef unsigned char uchar;
typedef struct {
    uchar a;
    uchar b;
    uchar c;
    uchar d;
} uchar4;

int main() {
    int theInt = 0xf0e1d2c3;
    uchar4 *p = (uchar4 *) &theInt;
    printf("%x %x %x %x\n", p->a, p->b, p->c, p->d);
    return 0;
}

Also: if sizeof(uint8) == 8, which of the DWORDs do you want your structure to be mapping?

egrunin
I have accounted for (1) and am aware of (2). Is there a better way of doing something like that without explicitly copying data? I know I'm knit-picking, but speed is very important for my system
bobbyb
Pointer aliasing is not going to help very much with speed.
dreamlax
i think it will if its replacing a lengthy memcpy or a manual copy via for loop
bobbyb
A: 

Behold, the humble union:

#include <stdio.h>

typedef struct {
    unsigned char x, y, z, w;
} xyzw;

typedef union {
    xyzw x;
    unsigned int i;
} ixyzw;


unsigned int xyzw_to_i(ixyzw *p)
{
    return p->i;
}

int main()
{
    xyzw x = {1, 2, 3, 4};

    printf("sizeof unsigned char %d\n", sizeof(unsigned char));
    printf("sizeof unsigned int  %d\n", sizeof(unsigned int));
    printf("sizeof xyzw          %d\n", sizeof(xyzw));
    printf("sizeof ixyzw         %d\n", sizeof(ixyzw));

    printf("xyzw = { %d, %d, %d, %d }\n", x.x, x.y, x.z, x.w);
    printf("i    = 0x%08x\n", xyzw_to_i((ixyzw *) &x));
    return 0;
}

which on my machine happens to yield:

sizeof unsigned char 1
sizeof unsigned int  4
sizeof xyzw          4
sizeof ixyzw         4
xyzw = { 1, 2, 3, 4 }
i    = 0x04030201

but one can't count on this behavior across compilers or machines.

msw
it may be humble, but it knows what its doing! thank you! maybe someday i can get it working without a union too.
bobbyb
Isn't this undefined behaviour? (I know it is for c++, don't know about standard c though)
Grant Peters
"Undefined" yes, where the compiler is free to order and align the data however it likes. "Undefined" in this context means "not at all portable", not "doesn't do anything" nor "is likely to give inconsistent interpretations on a given machine/compiler". Most operating systems count on this sort of "undefined" behavior somewhere inside the kernel especially when dealing with odd device registers.
msw
@bobbyb: if you are going to do this sort of cast abuse, I suggest you retain the union. This could have been done with only a cast, but the union makes is slightly more understandable to the reader. Exactly like a struct **definition**, a union definition uses no memory, it is just an declaration to the compiler that a chunk of memory can be interpreted as different types.
msw
A: 

Your compiler is aligning the struct members at a four byte boundary. That is why you only get every fourth byte (the rest are assumed to be padding space in the struct). To avoid this behavior you need to declare the struct packed. How it's done depends on the compiler (and not every compiler support it). With GCC you do it like this:

struct uchar4 {
    uchar a;
    uchar b;
    uchar c;
    uchar d;
} __attribute__((__packed__));
Grim