Jack
Jack

Reputation: 1438

typecasting bigger or smaller structure in C

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.

Upvotes: 2

Views: 5330

Answers (4)

Yousf
Yousf

Reputation: 3997

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.

Upvotes: 1

Dan Olson
Dan Olson

Reputation: 23367

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.

Upvotes: 1

Frank Krueger
Frank Krueger

Reputation: 70983

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;
};

Upvotes: 10

Marcelo Cantos
Marcelo Cantos

Reputation: 185852

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 };

Upvotes: 3

Related Questions