views:

365

answers:

4

I have two structures in C program: SmallStructABC and BigStructXYZ

I have several members in both of them; SmallStructABC's all 10 members are exactly same as first 10 members of BigStructXYZ. BigStructXYZ has 50 additional members.

Is it OK to type-cast this two structures to each other?

SmallStructABC *i = (BigStructXYZ*)j;
BigStructXYZ   *a = (SmallStructABC*)b; 

I only access first 10 (common) members after type-casting..

I wrote C program and its working fine on my machine. Just wanted to verify if I need to take care of any corner cases (alignment, invalid read, non-gcc compilation etc)..

EDIT: Q: Why I want to do something like this?

A: BigStructXYZ is very big in size (say 50KB) and contains some header (keys, map etc). I compress this data before sending over network. I leave header (in our case its SmallStructABC) as it is. By doing type-cast, I can access these keys from header as and when required.

+2  A: 

The code above won't compile. Is j already a BigStructXYZ, and did you mean to cast it to SmallStructABC?

Whatever the case, what you're trying to do is a bad idea. It would be better to have SmallStructXYZ as the first field inside BigStructXYZ and work thus:

SmallStructABC i = j.smallStruct;
BigStructXYZ a = { b };
Marcelo Cantos
+9  A: 

No, this is not a good idea. Much better would be to type cast pointers to the structures and manipulate them through the pointers:

void DoSomething(Small *thing) {
    // ...
}

int main() {
    Big big = {0};
    Small small = {0};

    Small *p0 = (Small*)&big;
    Small *p1 = &small;

    DoSomething(p0);
    DoSomething(p1);

    return 0;
}

An alternative and safer design is to define Big in terms of Small:

typedef struct Small {
    int foo;
};
typedef struct Big {
    Small small;
    int y;
};
Frank Krueger
I agree to this answer for my question. Although my design is bit more complex and this may not work straight away. Small and Big both have first 10 members common to them and Small has total 20 members and Big has 50 members. People will ask why not to make first 10 member as seperate structure and include it? I agree.. Sigh! thats not an option :(
Jack
Well I gave the pointer solution first because I understand that some designs can't be changed. But come on, this is C, your design can't (shouldn't) get that complex. :-)
Frank Krueger
I totally agree... But, changing this structures is not in my hand..
Jack
+1  A: 

I can think of cases where this wouldn't be guaranteed to work off the top of my head, but it should be fine on most platforms in most situations. One I'm thinking of off the top of my head is that alignment is supposed to be determined by the largest member of a struct, so if there was a 64 bit member or something else in the larger struct it could potentially affect the alignment of the first few members. I'm sorry that I don't have a more solid source or clearer explanation of this available at the moment.

In my own code I'd prefer to embed the header directly into the larger struct as mentioned in Frank Kreuger's answer and use a bigStruct.header.someMember type of interface to avoid any and all casting and alignment difficulties.

Dan Olson
A: 

Yes you can do it. SmallStructABC will take exactly the same location in memory as the first part of BigStructXYZ.

I used this with unions. The system receives a payload, it might be header or header+data.

I wrote union like this:

union HeaderOrHeaderData
{
    SmallStructABC header;
    BigStructXYZ headerData;
};

HeaderOrHeaderData* ptr = (HeaderOrHeaderData*) data_ptr;

The advantage of this method over direct casting is that may -by mistake- the pointer of bug struct (which actually point to small struct) and use it as it points to big struct.

If you always use the union, you will think twice.

I tried this solution with couple of compilers, operating systems and plateforms. It works fine at all times.

Yousf