Contrary to the top answer, I would say that bind
CAN and MUST be written in a way such that reinterpret_cast
is safe to use here. For instance, bind
could be implemented as:
int bind(SOCKET s, const sockaddr* addr, int addrlen) {
std::uint16_t address_family;
std::memcpy(&address_family, addr, sizeof(address_family));
if (address_family == AF_INET) {
const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(addr);
// Accessing sin->sin_addr is safe here
...
} else if (address_family == AF_INET6) {
const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(addr);
...
}
}
The key point is that the reinterpret_cast
itself is not UB, it's trying to access the data that's UB (see Type Aliasing):
Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined[...]
In the code above, we never try to read the contents of addr
through a pointer of type sockaddr*
. We examine the value representation (raw bytes) to get the address family, which tells us the exact type of struct to use. Then we can safely cast back to the original type. Casting to a pointer of a different type then back to the original type is allowed by the standard.
Taking it one step further, I would say that with sockaddr_in6
the implementation must handle reinterpret_cast
correctly. Since sizeof(sockaddr_in6) > sizeof(sockaddr)
, the memcpy
trick no longer works. The API is specifically asking for a pointer to an object of the wrong type, so the onus is on the API implementers to use the pointer correctly.
sockaddr
structs are designed in an opaque manner. IMO it's OK. – Pfefferreinterpret_cast
? Is there a specific part of the standard saying something like "if structs/classes X and Y begin with same fields then I can cast one to another and use common fields safely"? – Polingreinterpret_cast<struct sockaddr*>(&sa);
notreinterpret_cast<struct sockaddr*>(sa);
you forget&
or this is typo ? and usebind(sfd, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa));
absolute safe and correct – Autint*
intochar*
a withreinterpret_cast
. It's so preposterous I won't bother refuting it. – Foreshortenreinterpret_cast
tochar*
:AliasedType is char, unsigned char, or std::byte: this permits examination of the object representation of any object as an array of bytes.
, see "type aliasing" in the link. It's a special case. Anyway I don't think that the case I'm talking about falls into any category mentioned in the article about reinterpret_cast. Correct me if I'm wrong. – Polingstatic_cast<cv T2*>(static_cast<cv void*>(expression))
" – Foreshortenchar*
). And accessing the structure is UB (unlike cast tochar*
). Thus you can't achieve safely what I am talking about. Unless I'm wrong. Let's stick to the context of the question and not drift away. – Polingresa
, so it should be safe (yes,bind
will read fromresa
, but it is a presumable C lib, C++ rules doesn't apply). – Ingeingebergbind
is compiled to proper object code. I mean, ifbind
is compiled as just lto, it could fail in theory. But I still don't understand: youreinterpret_cast
(which is fine), then you give the resulting pointer tobind
.bind
can be implemented in any language, so it should work no matter how you call it. The only requirement is that the pointer should point to properly formatted bytes, which is true in your case. It would be ridiculous ifbind
cannot be called from C++ code. – Ingeingebergsa
? As I understand,resa
should point exactly to the same byte as&sa
points. – Ingeingebergbind
does the access, which is not covered by the C++ standard. – Ingeingebergresa
, since you aren't accessing or modifying any members through that pointer. [expr.reinterpret.cast] has me wondering, though: "Note: The mapping performed byreinterpret_cast
might, or might not, produce a representation different from the original value. — end note". That indeed implies, that the object representation of the pointer can change. I'm at a loss, what implications that has, but it makes me feel uncomfortable about the code. – Illuminative