No, this is not guaranteed to work.
First and foremost, there is no guarantee on the placement of unrelated objects in memory. The only times that objects are guaranteed to be placed contiguously in memory are
- if you put them next to each other yourself (e.g., you manually allocate some number of bytes and place them one after the other) or
- if they are in an array (array elements are always contiguous
So, the following is valid:
int ints[2];
*(&ints[0] + 1) = 42;
The code in the question is not valid because the foo and bar objects are entirely unrelated and could be placed anywhere in memory.
There is a somewhat related issue that within a struct there may be unnamed padding bytes either
- between members of the struct (so that members are correctly aligned) and
- at the end of the struct (so that objects of that struct type can be placed contiguously in an array)
This means that the following is not valid because there could be unnamed padding at the end of a Foo:
Foo foos[2];
*(&foos[0].a + 1) = 42;
As a rule, you should never rely on the placement of two objects relative to each other unless they are in an array. It doesn't matter whether the objects are declared next to each other in the source code, they have the same type, or they have the same size: there simply is no guarantee.