Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » casting structs

This thread is locked; no one can reply to it. rss feed Print
 1   2 
casting structs
Martin Kalbfuß
Member #9,131
October 2007
avatar

If I store a

typedef struct
{
  int a
  int b;
}
STRUCT_B;

cast into a

typedef struct
{
 int a;
}
STRUCT_A;

variable, is the value of int b lost?

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

X-G
Member #856
December 2000
avatar

You cannot cast structs.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Magemaster
Member #10,856
April 2009

I would think so since STRUCT_A is only reading one int block of memory, while STRUCT_B is reading two int size blocks of memory.

X-G, download mappyal and look at mappyal.c Pay attention to the (BLKSTR *) type casts.

Martin Kalbfuß
Member #9,131
October 2007
avatar

I cannot cast structs?

Now I'm really surprised. :o

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

Matthew Leverton
Supreme Loser
January 1999
avatar

You cast a pointer to a struct. In C, you can cast any type to any other type.

No data will be "lost," but the compiler won't let you at something that the current assumed type doesn't "know about."

Martin Kalbfuß
Member #9,131
October 2007
avatar

So

STRUCT_A struct_a = (STRUCT_A)struct_b;

isn't allowed. Only

STRUCT_A * struct_a = (STRUCT_A*)&struct_b;


???

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

BAF
Member #2,981
December 2002
avatar

Why do you want to do this? :o

Magemaster
Member #10,856
April 2009

When you declare STRUCT_A it is declared into memory:
|A|?|?|?|
Since it contains one integer it takes up one block of memory(hypothetically)

When you declare STRUCT_B it is declared into memory:
|B|B|?|?|
With two integers it takes up two blocks.

If you do (STRUCT_A)struct_b;
only the first block of B is going to be read since STRUCT_A only takes one block of memory.

if you (STRUCT_B)struct_a;
the int in STRUCT_A will be read, along with who know what in the next block of memory since STRUCT_B calls for two blocks of memory.

X-G
Member #856
December 2000
avatar

download mappyal and look at mappyal.c Pay attention to the (BLKSTR *) type casts.

That's a pointer cast, not a struct cast.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Schyfis
Member #9,752
May 2008
avatar

So if you do STRUCT_A struct_a = (STRUCT_A)struct_b; and the original reference to struct_b is lost by going out of scope, will the struct remain intact if cast to STRUCT_B at a later time?

________________________________________________________________________________________________________
[freedwill.us]
[unTied Games]

Kitty Cat
Member #2,815
October 2002
avatar

Polymorphism in C can be accomplished by:

struct STRUCT_A {
    int a;
};

struct STRUCT_B {
    struct STRUCT_A parent; // must be first!
    int b;
};

Then a pointer to STRUCT_B is also a valid pointer to STRUCT_A. You can also get a non-pointer-to STRUCT_A from a STRUCT_B without casting, by using STRUCT_B's 'parent' member.

struct STRUCT_B myB;
struct STRUCT_A *pA;

pA = &myB.parent;
// &myB == pA will be true
// modifying myB.parent.a will also modify pA->a

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Timorg
Member #2,028
March 2002

If you need this behaviour, you could also use a union...

#SelectExpand
1#include <stdio.h> 2 3struct STRUCT_A { 4 int a0; 5}; 6 7struct STRUCT_B { 8 int b0; 9 int b1; 10}; 11 12union DATA 13{ 14 struct STRUCT_A a; 15 struct STRUCT_B b; 16}; 17 18 19int main() 20{ 21 union DATA d; 22 23 d.b.b0 = 10; 24 d.b.b1 = 15; 25 26 printf("d.a = %d", d.a.a0); 27 28 return 0; 29}

Which gives the output...

d.a = 10

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Kitty Cat
Member #2,815
October 2002
avatar

I don't think such alignment is guaranteed within a union. AFAIK, a0 could be aligned to b0 or b1.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Timorg
Member #2,028
March 2002

I thought that was one of the uses of unions, and is something you can rely on.

http://msdn.microsoft.com/en-us/library/5dxy4b7b(VS.80).aspx said:

#SelectExpand
1// using_a_union.cpp 2#include <stdio.h> 3 4union NumericType 5{ 6 int iValue; 7 long lValue; 8 double dValue; 9}; 10 11int main() 12{ 13 union NumericType Values = { 10 }; // iValue = 10 14 printf_s("%d\n", Values.iValue); 15 Values.dValue = 3.1416; 16 printf_s("%f\n", Values.dValue); 17}

Output:
10
3.141600

The NumericType union is arranged in memory (conceptually) as shown in the following figure.

{"name":"5dxy4b7b.Local_-567443686_vc38ul1(en-US,VS.80).gif","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/d\/ed6b1fce93576f0105ee891492bc9989.gif","w":256,"h":71,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/d\/ed6b1fce93576f0105ee891492bc9989"}5dxy4b7b.Local_-567443686_vc38ul1(en-US,VS.80).gif

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Arthur Kalliokoski
Second in Command
February 2005
avatar

Yes, MS is well known for compatibility, portability, and adhering to standards. ::)

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

Timorg
Member #2,028
March 2002

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Kitty Cat
Member #2,815
October 2002
avatar

As long as the types in the union are all the same size, they will be aligned (eg. a packed 4 1-byte struct will align with a 4-byte int). But I don't think the C standard guarantees that a 4-byte type, for example, will align with the first or last four bytes of an 8-byte type. Endianess can also throw off which bytes are aligned with what.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Timorg
Member #2,028
March 2002

They both start at the same memory address, so the first items will be at the same point. Which is what the example was for. As for the later items in the structs, it depends on the packing of the variables.

GCC controls the packing with the aligned and packed attributes, but both MSVC and GCC align the first variables. I don't know how to specify the packing on MSVC.

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Matthew Leverton
Supreme Loser
January 1999
avatar

Tobias Dammers
Member #2,604
August 2002
avatar

Kitty Cat said:

As long as the types in the union are all the same size, they will be aligned (eg. a packed 4 1-byte struct will align with a 4-byte int). But I don't think the C standard guarantees that a 4-byte type, for example, will align with the first or last four bytes of an 8-byte type. Endianess can also throw off which bytes are aligned with what.

The sizes of the various types may differ between compilers and platforms. Even if two types are of the same size on one platform, they may not be on another. In my experience, brute-force casting like this isn't portable, and you're best off avoiding this kind of thing (in most cases, there are better ways).

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Kitty Cat
Member #2,815
October 2002
avatar

The sizes of the various types may differ between compilers and platforms.

Unless you use the types like uint32_t or int8_t defined in C99. Oh wait...

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Martin Kalbfuß
Member #9,131
October 2007
avatar

I'm using C99, so I could use these types. And I yes, I try to have polymorphism.

The problem is that my objects are on the stack. And because I cannot store a derived object in an parents objects space, because I can only cast basic types. I have to to something like this which isn't nice.

STRUCT_A a = STRUCT_A__Construct( ... );
STRUCT_B b = STRUCT_B__Construct( ... )
STRUCT_C c = STRUCT_C__Construct( ... );

STRUCT_BASE * structs[3] = { &a, &b, &c };

Is it possible to do something like

int main( void )
{

   STRUCT_BASE * structs[3] = { (STRUCT_BASE *)&STRUCT_A__Construct( ... ),
                                                   (STRUCT_BASE *)&STRUCT_B__Construct( ... ), 
                                                   (STRUCT_BASE *)&STRUCT_C__Construct( ... ) };

   ...

}

Are the original variables exsistent in the functions scope? Or isn't this possible?

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

Kitty Cat
Member #2,815
October 2002
avatar

You have to use pointers to use polymorphism. It's true in C++ as well as C. It's not valid to take a pointer to a returned object like that. What I would do instead is:

#SelectExpand
1STRUCT_A *new_STRUCT_A(...) 2{ 3 STRUCT_A *ret = malloc(sizeof(STRUCT_A)); 4 ...initialize ret with the params... 5 return ret; 6} 7STRUCT_B *new_STRUCT_B(...) 8{ 9 STRUCT_B *ret = malloc(sizeof(STRUCT_B)); 10 ...initialize ret with the params... 11 return ret; 12} 13STRUCT_C *new_STRUCT_C(...) 14{ 15 STRUCT_C *ret = malloc(sizeof(STRUCT_C)); 16 ...initialize ret with the params... 17 return ret; 18} 19 20... 21 22int main( void ) 23{ 24 STRUCT_BASE * structs[3] = { (STRUCT_BASE*)new_STRUCT_A(...), 25 (STRUCT_BASE*)new_STRUCT_B(...), 26 (STRUCT_BASE*)new_STRUCT_C(...) }; 27 // or, with the structs having a 'parent' member that's a STRUCT_BASE type as 28 // the first member.. 29 STRUCT_BASE * structs[3] = { &new_STRUCT_A(...)->parent, 30 &new_STRUCT_B(...)->parent, 31 &new_STRUCT_C(...)->parent }; 32 ... 33 34}

(don't forget to free the STRUCT_BASE pointers, or else you'll leak). At that point, though, you're starting to re-implement C++ in C.. you'd probably be better off using C++.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

William Labbett
Member #4,486
March 2004
avatar

STRUCT_A new_STRUCT_A(...)  
{   
   STRUCT_A *ret = malloc(sizeof(STRUCT_A));  
 ...initialize ret with the params... 
   return ret;  
}

The return type is STRUCT_A but ret is a STRUCT_A *. Isn't that wrong ?

Tobias Dammers
Member #2,604
August 2002
avatar

It is, and probably a typo. The function needs to return a pointer.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

 1   2 


Go to: