Will this trick work in C?

后端 未结 5 959
终归单人心
终归单人心 2021-01-21 15:50

I want to add a field to a structure in C. So for example I have the following structure.

struct A
{
 some_type x;
 some_type y;
}

I declare a

相关标签:
5条回答
  • 2021-01-21 16:32

    Yes, this would work, but only by accident.

    If I recall the C99 standard correctly, this particular case is specifically required to work as you expect. But it's clear that this is only because sufficiently many people relied on it working before that, and it did work by accident in sufficiently many implementations, that the C99 standards committee felt obliged to legislate for it working de jure as well as de facto.

    Don't let that tempt you into thinking that this is a good idea.

    Anything which relies on standards edge-cases is permanently teetering on the edge of brokenness, because it looks hacky (and so makes your code's future readers uncomfortable) and looks clever (which makes them nervous of changing/fixing anything). Also it leads folk into making assumptions which, because you're already on the edge of what's legitimate, can tempt folk across the border into broken code. For example, the fact that the first element within the first sub-struct within a struct is aligned as you expect, does not imply that any other sub-elements are lined up. That fact that it works for your compiler does not imply that it'll work for anyone else's, leading to mind-bendingly confusing bugs.

    Write:

    A *a = &(b->a);
    

    (as the comment above suggests) and your meaning is clear.

    If for some obscure reason you have to cast B* to A*, then write a very clear comment explaining why you have no option but to do what you have to do, assuring the reader that it is legitimate, and pointing to the subsubsection of the C99 standard which licenses it.

    If you really cannot find that subsection (and finding it is your homework/penance), then comment thus and I'll dig it up.

    0 讨论(0)
  • 2021-01-21 16:34

    Why not just call the method on the member?

    some_function( &b->a );
    

    Your code works now, but what if somebody decides to change the members of B? Or add a new member before a?

    0 讨论(0)
  • 2021-01-21 16:46

    No it won't work. It would work if you change it a bit:

    struct A
    {
     some_type x;
     some_type y;
    }; /* <- note semicolon here */
    
    
    struct B
    {
     struct A a;
     some_type z;
    }; /* ... and here */
    
    
    int some_function(struct A *a ); /* ... and here ... */
    
    
    struct B *b;
    ......
    struct A *a = (struct A*)b;
    some_function( a );
    
    0 讨论(0)
  • 2021-01-21 16:55

    Yes, it is valid. Word of the Standard, C99 6.7.2.1/13:

    ... A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

    0 讨论(0)
  • 2021-01-21 16:55

    Yes, it would work. A a will be the first member in the struct

    This is how some people simulated OO inheritance in C

    You may use

      &b->a
    

    instead of the cast. And probably do an ASSERT like

     ASSERT (&b->a == b)
    

    to be warned when you accidentally destroyed this semantic

    0 讨论(0)
提交回复
热议问题