|
This thread is locked; no one can reply to it. |
1
2
|
casting structs |
Martin Kalbfuß
Member #9,131
October 2007
|
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 |
X-G
Member #856
December 2000
|
You cannot cast structs. -- |
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
|
I cannot cast structs? Now I'm really surprised. http://remote-lisp.spdns.de -- my server side lisp interpreter |
Matthew Leverton
Supreme Loser
January 1999
|
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
|
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 |
BAF
Member #2,981
December 2002
|
Why do you want to do this? |
Magemaster
Member #10,856
April 2009
|
When you declare STRUCT_A it is declared into memory: When you declare STRUCT_B it is declared into memory: If you do (STRUCT_A)struct_b; if you (STRUCT_B)struct_a; |
X-G
Member #856
December 2000
|
Magemaster said: download mappyal and look at mappyal.c Pay attention to the (BLKSTR *) type casts. That's a pointer cast, not a struct cast. -- |
Schyfis
Member #9,752
May 2008
|
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? ________________________________________________________________________________________________________ |
Kitty Cat
Member #2,815
October 2002
|
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
-- |
Timorg
Member #2,028
March 2002
|
If you need this behaviour, you could also use a union... 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 ____________________________________________________________________________________________ |
Kitty Cat
Member #2,815
October 2002
|
I don't think such alignment is guaranteed within a union. AFAIK, a0 could be aligned to b0 or b1. -- |
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:
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: 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"}
____________________________________________________________________________________________ |
Arthur Kalliokoski
Second in Command
February 2005
|
Yes, MS is well known for compatibility, portability, and adhering to standards. They all watch too much MSNBC... they get ideas. |
Timorg
Member #2,028
March 2002
|
That was just an example with an image, you could also look at http://www.anyexample.com/programming/cplusplus/example_of_using_union_in_cplusplus.xml ____________________________________________________________________________________________ |
Kitty Cat
Member #2,815
October 2002
|
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. -- |
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. ____________________________________________________________________________________________ |
Matthew Leverton
Supreme Loser
January 1999
|
#pragma pack(n) |
Tobias Dammers
Member #2,604
August 2002
|
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). --- |
Kitty Cat
Member #2,815
October 2002
|
Tobias Dammers said: 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... -- |
Martin Kalbfuß
Member #9,131
October 2007
|
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 |
Kitty Cat
Member #2,815
October 2002
|
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: 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++. -- |
William Labbett
Member #4,486
March 2004
|
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
|
It is, and probably a typo. The function needs to return a pointer. --- |
|
1
2
|