The standard specifies behaviors of things, not how are they implemented. The implementation part is left to implementators - people who write compilers and libraries - and they have to implement things in a way they work in a way specified by the standard. If that implementation of standard library has by itself undefined behavior is irrelevant - it has to work with specified compiler, so specific compiler will interpret it in a way it has the behavior implementators want. Undefined behavior means that the standard specifies no requirement on the behavior of code. Your compiler documentation may specify additional requirements specifying behaviors of code that according to the standard are undefined - thus the code may be undefined by the standard and be perfectly fine and reasonable on a specific compiler that is required/written to interpret it in that way.
C++ language uses macros from C language when proper #include
is used. The C standard says C99 7.17p3:
The macros are [...] and
offsetof(type, member-designator)
which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that given
static type t;
then the expression &(t.member-designator) evaluates to an address constant. (If the specified member is a bit-field, the behavior is undefined.)
As a user of the language you do not care how it's implemented. If you use a standard compliant compiler, whatever it does behind the scenes, it should result in the behavior specified by the standard. Your usage of offsetof(PerObjBuffer, sampleType)
is valid - having static PerObjBuffer t;
then &(t.member-sampleType)
evaluates to address constant - so offsetof(PerObjBuffer, sampleType)
evaluates to integer constant expression. You like do not care how the compiler arrives at the result - it can use dark magic to do it - what matters it that compiler does it and the result represents the offset in bytes. (I think the famous example is memcpy
- it's not possible to implement memcpy
in standard compliant way, yet the function... exists).
Still, I fear that other parts of your code will be very invalid. The memcpy
will most probably result in undefined behavior - you will copy padding between members and you seem to want to send that to some hardware location. In any case, I advise to do extensive research on lifetime and representation of C++ objects, on padding within structures, types of objects (ie. POD
/standard layout/trivial) and how to work with them (ie. when it's ok to use mem*
functions/placement new/std::launder
).