简体   繁体   中英

How to correctly cast a pointer-to-struct to pointer-to-other-struct in modern C++ when calling legacy C API?

When calling a legacy C API such as getnameinfo , what's the right way in modern C++ to correctly cast a pointer-to-struct argument to a pointer-to-another-struct, which has similar layout, but which isn't related to the class hierarchy of the original struct?

For example, getnameinfo accepts for its first parameter a const struct sockaddr * , but it should also work when handing it a const struct sockaddr_storage * . However, AFAIK simply reinterpret_cast -ing the pointer is considered UB by the C++ standard.

In the above example, given a sockaddr_storage object, what's the right way to pass a pointer to it to getnameinfo ?

I may be misreading the standard, but since those types are standard layout types, it's not UB if you access their common initial sub-sequence. I believe [class.mem/23] is why:

In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.

This is an explicit permission for unions, that theoretically could simply be accomplished with compiler magic. But in effect I believe it means that for standard layout classes, the common initial sequence has the same layout in memory.

Now let's consider [basic.lval/8.6] :

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • ...
  • an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
  • ...

When you dereference the reinterpreted pointer, you obtain a glvalue of an aggregate that includes the type of the member you access. Since that member belongs to the common initial sequence, all should be well.

I doubt there's a sane implementation where this will not work across a library boundary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM