Thread: Question about safety/coding practices (casting between structs)

  1. #1
    Registered User
    Join Date
    May 2010
    Posts
    269

    Question about safety/coding practices (casting between structs)

    Suppose I have two structs, one of which can be considered an extension of another... is it safe to do this:

    Code:
    typedef struct _original
    {
      int field1;
      double field2;
    } original;
    
    typedef struct _extended
    {
      int field1;
      double field2;
      char * metadata;
    } extended;
    
    int main(int argc, char ** argv)
    {
      original * org = malloc(sizeof(original));
      org->field1 = 10;
      org->field2 = 11.11;
    
      extended * ext = (extended *)org;
      ext->metadata = "metadata";
      printf("%d %lf %s\n",ext->field1, ext->field2, ext->metadata);
    }
    The print shows that the new struct ext has all of the right information.

    I guess the other way would be to copy the information directly, but such memory copies cause unnecessary slowdown.

    Is it OK for me to do the casting that way?

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Yes. Beware that it is not a copy, however, it's a pointer to the same memory address, so if you change org, ext will change, and vice versa.

    If you do want a copy, you can copy the same way (using a cast and the = assignment operator), but obviously ext will have to have some memory allocated to it first.

    Code:
    	extended *ext = malloc(sizeof(extended));
    	*ext = *((extended*)org);
    * dereferences the pointers to yield their value, which is the contents of the struct.
    Last edited by MK27; 05-06-2011 at 03:34 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by dayalsoap View Post
    Suppose I have two structs, one of which can be considered an extension of another... is it safe to do this:
    They are not guaranteed to be padded the same.
    Quote Originally Posted by dayalsoap View Post
    I guess the other way would be to copy the information directly, but such memory copies cause unnecessary slowdown.
    This is called "premature optimization".


    Quzah.
    Hope is the first step on the road to disappointment.

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    269
    Quote Originally Posted by quzah View Post
    They are not guaranteed to be padded the same.This is called "premature optimization".


    Quzah.
    So what are some caveats I would have to worry about if they're not padded the same?

    I disagree that this is premature optimization. Copying is one of the largest sources of error in HPC applications, particularly when it's across address spaces (this isn't but copies on an elements of over 100mb in size will take along time)

  5. #5
    Registered User
    Join Date
    May 2010
    Posts
    269
    I don't think this falls under premature optimization. Memory copies are a huge source of latency in HPC applications, especially when they're across address spaces (hence DMA). This is within the same address space, but never the less, copying elements from a 100Mb struct will add unnecessary latency.

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    269
    Thank you. I am doing this so I can avoid the copy. Are there any caveats that I have to worry about? Quzah mentioned that the padding might not be the same...

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    269
    Hmm, it's interesting to me that it worked.. since when I malloc'ed, I only malloc'ed for the size of original, yet I was able to assign a value to metadata in extended.... shouldn't there not have been space for the extra char *?

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Why do you think copying a structure is any different than copying a structure's elements? You are still moving the same amount of data. It's not suddenly magic because you are copying a structure rather than an integer or a string or whatever else you are copying.


    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by MK27 View Post
    Yes. Beware that it is not a copy, however, it's a pointer to the same memory address, so if you change org, ext will change, and vice versa.
    You are both wrong, here is why:
    Quote Originally Posted by dayalsoap View Post
    Hmm, it's interesting to me that it worked.. since when I malloc'ed, I only malloc'ed for the size of original, yet I was able to assign a value to metadata in extended.... shouldn't there not have been space for the extra char *?
    C will gleefully let you trash your memory.


    Quzah.
    Hope is the first step on the road to disappointment.

  10. #10
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    You could do this.
    Code:
    struct base {
         int field1;
      double field2;
    };
    struct extend {
      struct base b;
      char * metadata;
    };
    Then 
    	struct extend *p = &(struct extend) { (struct base) {3, 1.0}, "hello" };
    	struct base *b;
    	b = (struct base*)p;
    	printf("%d %f\n",b->field1,b->field2);
    Standard grantees that There will be no padding in front of first member of struct.
    Take note that you're not doing any *copy* here!
    Just pointing!
    It's just like upcasting and downcasting.
    up cast is safe.
    Last edited by Bayint Naung; 05-06-2011 at 03:43 PM.

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    There isn't room for that char *, but remember, C doesn't track the bounds of the memory you allocate, so you can happily write past the end of the original struct you allocated. You only generate a page/segmentation fault when you go outside of that page/segment. The page/segment protection like read only or read-write applies to whole pages, not individual pieces of malloc'ed memory, so you'd have to write off the end of the page. Presumably, your page size is bigger than the 8 bytes allocated for the original struct, and malloc gave you a chunk of memory that wasn't at the very end of a page, hence no crash. Note that you still technically have undefined behavior, which is bad. Anything or nothing at all can happen, and it can happen immediately, soon or much later. It's a "just because you can, doesn't mean you should" type of thing.

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Bayint Naung View Post
    Take note that you're not doing any *copy* here!
    Just pointing!
    It's just like upcasting and downcasting.
    up cast is safe.
    Good catch on the copy. But I think you have that backwards. You can make "origin" point at "extended", and safely use all of "orign"'s elements, but if you do it the other way around, you'll trash your memory.

    For some reason I was thinking he was copying one to the other. But anyway, he still can't point the way he was and expect to magically be able to use all of "extended".


    Quzah.
    Hope is the first step on the road to disappointment.

  13. #13
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by dayalsoap View Post
    Suppose I have two structs, one of which can be considered an extension of another... is it safe to do this:
    One soution to this problem is to use a union... (You will see this in windows occasionally where they've changed a struct)
    Code:
    typedef union torig
      { int field1;
         double field2; 
        struct ext
          {  int field1;
             double field2;
            char metadata[256]; }
          }  ORIG, *pORIG;
    
    
    int main(int argc, char ** argv)
    {
      pORIG * org = malloc(sizeof(ORIG));
      org->field1 = 10;
      org->field2 = 11.11;
      strcpy(org->ext->metadata, "This is a test");  
    
      printf("%d %lf %s\n",org->ext->field1, org->ext->field2, org->ext->metadata);
    }
    Then there's nothing to copy and you can access it either way...

    (BTW... I haven't done this one in a while, someone should probably check my syntax)
    Last edited by CommonTater; 05-06-2011 at 04:05 PM.

  14. #14
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by CommonTater View Post
    Code:
    typedef union torig
      { int field1;
         double field2; 
        struct ext
          {  int field1;
             double field2;
            char metadata[256]; }
          }  ORIG, *pORIG;
    (BTW... I haven't done this one in a while, someone should probably check my syntax)
    It would be more like:
    Code:
    union u
    {
        struct origin o;
        struct extended e;
    };
    Otherwise 'field1' and 'field2' would share the same spot in memory, as would 'struct ext', but 'ext' doesn't actually have any variable name, so you wouldn't be able to access it (actually I don't think it wouldn't compile).


    Quzah.
    Hope is the first step on the road to disappointment.

  15. #15
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by quzah View Post
    It would be more like:
    Code:
    union u
    {
        struct origin o;
        struct extended e;
    };
    Otherwise 'field1' and 'field2' would share the same spot in memory, as would 'struct ext', but 'ext' doesn't actually have any variable name, so you wouldn't be able to access it (actually I don't think it wouldn't compile).


    Quzah.
    Ok... that's one way to do it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. [ noob question ] Help with structs within structs
    By Riverfoot in forum C Programming
    Replies: 3
    Last Post: 04-26-2011, 07:24 PM
  2. coding practices
    By pobri19 in forum C++ Programming
    Replies: 2
    Last Post: 07-17-2008, 04:56 PM
  3. Structs, members, and casting
    By Nick Howes in forum C Programming
    Replies: 4
    Last Post: 03-05-2008, 12:54 PM
  4. read-only data members. A question of good practices
    By Mario F. in forum C++ Programming
    Replies: 11
    Last Post: 06-19-2006, 04:35 AM
  5. Thread Safety Question
    By Geolingo in forum C++ Programming
    Replies: 4
    Last Post: 05-08-2004, 11:35 AM