The question: Can the output of the below program be predicted reliably, given the full code for B
and C
?
If the answer is "no" (e.g. due to platform dependence), then: Is there a way to make it predictable (e.g., by using certain allocation/alignment techniques).
struct B{
// ...
};
struct C{
// ...
};
struct A{
B b;
C c;
};
int main(){
A a;
long db = (int*)(&a.b) - (int*)(&a );
long dc = (int*)(&a.c) - (int*)(&a.b);
std::cout << "difference a.b to a : " << db << "\n";
std::cout << "difference a.c to a.b : " << dc << "\n";
}
Remark(s):
int*
is just because cpp disallows use of void*
afaik.db,dc
to compute the address of b
and c
from a given object of A
at another compile time.The answer is yes, provided that B
and C
have the same size and alignment across platforms. For example, a struct such as this:
struct meow {
int a;
void* b;
};
won't have the same size and alignment across multiple platforms. The above would (most likely) be of size 8 on a 32 bit platform (int
s are usually 32 bit but that's not guaranteed) and of size 16 on a 64 bit platform (64bit pointer and 8 byte allignment). So, member offsets may be different.
In order to have a "predictable" offset for your members, be sure to avoid pointers (different size on each platform unless you target either 32 or 64 bit platforms exclusively), standard types such as int
(which are implementation defined) and, of course, standard library types (implementation defined as well).
#include <cstdint>
struct meow { // size 28, alignment 4
int32_t a; // Offset 0, guaranteed to be 32 bits, alignment 4
float b; // Offset 4, guaranteed to be 32 bits, alignment 4
char c[20]; // Offset 8, *usually* a char is 8 bits, alignment 1
};
The above is just a sample, you can adjust depending on your needs and the different platforms you want to accommodate.
Overall this is a good read: https://en.cppreference.com/w/c/language/object