Like Tree2Likes

Structures as members of structures & offset

This is a discussion on Structures as members of structures & offset within the C Programming forums, part of the General Programming Boards category; Code: void main() { struct a { struct b { int i; float f; }x; struct c { int j; ...

  1. #1
    Registered User
    Join Date
    Nov 2009
    Posts
    43

    Structures as members of structures & offset

    Code:
    void main()
    {
     struct a
     {
       struct b
       {
         int i;
         float f;
       }x;
    
       struct c
       {
         int j;
         float g;
       }y;
     }z;
    
     fun(&z.y);
    }
    
    void fun(struct c * p)
    {
      int offset;
      struct b * address;
    
       offset = (char *) & ((struct c *) (&((struct a *)0) -> y) -> j) - (char *)((struct    a*)0); 
    
       address = (struct b *)((char *) & (p -> j) - offset);
       address -> i = 200;
    }
    Can anyone explain how exactly are the two lines inside fun() that are assigning values to offset & address working ?

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    I think "barely" is the word you're looking for. Actually, I'm a little concerned about "(&((struct a *)0) -> y)"; presumably the compiler can figure out not to follow the null pointer, but that's what you're trying to make it do.

    In theory, you're figuring out the offset of the struct c inside your struct a (by pretending you have such an object at address 0), then using that to do some trickery to go "backwards" to get to the struct b inside your function when it has been passed in the struct c object. (Heaven forbid you use "offsetof", or just actually do something legal and pass in the struct a object itself.)
    stahta01 likes this.

  3. #3
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,866
    Ok, first of I noticed the code snippet you provided used void main(). This is no longer standards compliant as I am sure you know but to allow myself to sleep tonight I feel obligated to post the link on how main() should be defined.

    Second, my disclaimer: The following discussion involves code that is not standards compliant. According to ISO standard you cannot dereference a NULL pointer or perform some of these variable aliases. This results in undefined behavior which means the results vary from implementation to implementation.

    Third, sometimes things like this are useful and have been used in OS development where the developers are allowed to make assumptions on how the code will react. I mean, h**l even John Carmack used goto.

    So let's take a look at that first piece of code:
    Code:
    offset = (char *) & ((struct c *) (&((struct a *)0) -> y) -> j) - (char *)((struct    a*)0);
    The first part is the easy part, we will cast the result to type char* which is the type of actual memory addresses. Now the second part:
    Code:
    (struct c *) (&((struct a *)0) -> y) -> j)
    The ((struct a*)0) performs a trick which returns the base address for struct a. Having an address of a is the same as a pointer to 'a' so to access the members of object 'a' with ptr 'a' you would use pointer notation e.g. a->y->j. Then we obtain the address of j with &j.

    The next part of the line:
    Code:
    (char *)((struct    a*)0);
    Performs the same trick that we talked about above, e.g. it returns the base address of a. So now for offset we are performing this calculation:
    Code:
    offset = (address of j) - (address of a)
    This gives us the number of bytes from the start of struct 'a' that the j member is located.

    Now on to the next piece:
    Code:
    address = (struct b *)((char *) & (p -> j) - offset);
    With the above knowledge this is a little easier to tackle. So we are tacking the actual memory address of member j with this line &(p->j). The char* we discussed above.

    So with the actual memory address of j we are subtracting offset which as we discussed is the number of bytes from the begginning of the struct. So we are doing:
    Code:
    address = (address of j) - (number of bytes into the structure j is)
    Since math works, we now have the actual memory address of the first thing in struct 'a', which if you look at the definition for the struct you see that the first thing in struct 'a' is struct b.

    So now we have the memory address of struct b, which is the same as having a ptr to struct b. *note we casted the memory address to pointer type struct b above so the compiler would know about the members*

    So with that ptr we can assign values the way you would do pointers, e.g.
    Code:
    address->i=200;
    That about sums it up, let me know if you have any questions.
    Last edited by AndrewHunter; 07-15-2011 at 11:49 PM.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    This seems like an awfully convoluted way of just doing:
    Code:
    void *p = &z.x.i;
    If you have a way to directly access the member, which you do, given that you are directly querying them to find out where they are, then you don't need to find the offset.

    Anyway, this wouldn't even compile. func has no idea what a "struct b" or a "struct c" is.


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

  5. #5
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,866
    It is a convoluted way of doing things, and yes structure would have to declared outside of main. I believe this was just a code snippet with the actual question being the logic behind what was happening in the function.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  6. #6
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by AndrewHunter View Post
    It is a convoluted way of doing things, and yes structure would have to declared outside of main. I believe this was just a code snippet with the actual question being the logic behind what was happening in the function.
    Oh, you mean one of those "Lets all waste our time on this, so we don't have enough time to learn anything worthwhile" kinds of questions...
    AndrewHunter likes this.

  7. #7
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by CommonTater View Post
    Oh, you mean one of those "Lets all waste our time on this, so we don't have enough time to learn anything worthwhile" kinds of questions...
    I hate questions like that, because they don't actually teach you anything, because they are completely impractical, and no one would ever write that problem that way. I mean it's not like you don't know the member's name, because you are explicitly naming i when you assign 200 to it, and if you can do that, you don't need to find its offset, because you can just take its address directly.


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

  8. #8
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,866
    Quote Originally Posted by CommonTater View Post
    Oh, you mean one of those "Lets all waste our time on this, so we don't have enough time to learn anything worthwhile" kinds of questions...
    Haha....well basically yes. However this was the basic method the offsetof() macro use to be implemented prior to the whole standards thing. Also, you can find this hackery within *nix implementations. I am not sure of M$, because those guys don't believe in the whole open source thing. (I actually think their OS's run on orphan tears and unicorn blood )
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  9. #9
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by quzah View Post
    I hate questions like that, because they don't actually teach you anything, because they are completely impractical, and no one would ever write that problem that way. I mean it's not like you don't know the member's name, because you are explicitly naming i when you assign 200 to it, and if you can do that, you don't need to find its offset, because you can just take its address directly.
    Quzah.
    Yeppers .... z.y.j = 10; just about does it for me.

  10. #10
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,866
    Quote Originally Posted by quzah View Post
    I hate questions like that, because they don't actually teach you anything, because they are completely impractical, and no one would ever write that problem that way.
    Quzah.
    I am going to go with yes and no on this one. When you want to learn something you are going to want to just focus on the problem at hand. This type of hackery has been used in the past and is still being used, as I mentioned above. Why would you worry about coming up with a complex problem that would require this type of referencing when all you are worried about is how this type of referencing works.
    [$0.02]
    With the line of logic you are suggesting, I could be misunderstanding you btw, why bother to write the traditional "Hello World" program. I mean what use is that? Who would ever just need to know how to print "Hello World" to the screen? Might as well just start to learn programming by designing a GUI word processor, at least that is a real world problem that would teach you real world skills.
    [/$0.02]
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by AndrewHunter View Post
    With the line of logic you are suggesting, I could be misunderstanding you btw, why bother to write the traditional "Hello World" program.
    The traditional "Hello World" program is used to test compiler setups. If it compiles that, you're pretty close to a working setup.

    So, despite it's embarassing simplicity it does have a practical purpose.

  12. #12
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,866
    Quote Originally Posted by CommonTater View Post
    The traditional "Hello World" program is used to test compiler setups. If it compiles that, you're pretty close to a working setup.

    So, despite it's embarassing simplicity it does have a practical purpose.
    See, that is why I like this board.

    I think we all know what I am getting at though.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  13. #13
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by AndrewHunter View Post
    [$0.02]
    With the line of logic you are suggesting, I could be misunderstanding you btw, why bother to write the traditional "Hello World" program. I mean what use is that? Who would ever just need to know how to print "Hello World" to the screen? Might as well just start to learn programming by designing a GUI word processor, at least that is a real world problem that would teach you real world skills.
    [/$0.02]
    If I need to know the offset of a variable, I can simply use offsetof. If I don't want to, I can still do it:
    Code:
    void *p = &somestruct;
    void *q = &somestruct.member;
    int ptrdif = q - p;
    Why on earth would I ever do what they are doing?


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

  14. #14
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,866
    In *nix they use it for container_of() or whatever it is called. And offsetof() use to use this type of hackery to accomplish it's task. All I am saying is even though the example was over simplified it demonstrated a memory accessing technique and the OP just wanted to know how that technique worked. Simple as that.

    The OP may decide that they want to go on and make a compiler or OS for themselves and may run into a situation where they would need to use something like this to solve a problem. I believe I explained that in my second and third point of my original post.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  15. #15
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by AndrewHunter View Post
    In *nix they use it for container_of() or whatever it is called. And offsetof() use to use this type of hackery to accomplish it's task. All I am saying is even though the example was over simplified it demonstrated a memory accessing technique and the OP just wanted to know how that technique worked. Simple as that.

    The OP may decide that they want to go on and make a compiler or OS for themselves and may run into a situation where they would need to use something like this to solve a problem. I believe I explained that in my second and third point of my original post.
    Your second point in your first post explains why there is no right answer to his question. If it invokes undefined behavior then you cannot say it gives you a set result. Which would not only makes it a pointless exercise, it would be unreliable at best.


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

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. structures and pointers and members
    By Striker87 in forum C Programming
    Replies: 3
    Last Post: 04-18-2011, 10:54 PM
  2. passing static structures members to function
    By bhagwat_maimt in forum C++ Programming
    Replies: 0
    Last Post: 11-17-2006, 03:13 AM
  3. Changing a Structures Members array size
    By Xei in forum C++ Programming
    Replies: 1
    Last Post: 11-07-2002, 06:45 PM
  4. Help with pointers and members of structures
    By klawton in forum C Programming
    Replies: 2
    Last Post: 04-19-2002, 12:34 PM
  5. Accessing members of structures
    By Nutshell in forum C Programming
    Replies: 6
    Last Post: 02-03-2002, 11:10 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21