The compiler produces this warning when I'm working with some code which looks like -
....
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer = "IPv0";
if(p->ai_family == AF_INET) {
ipVer = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else {
ipVer = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
....
}
where p = res
are of type struct addrinfo
and the types producing warnings are sockaddr_in
and sockaddr_in6
. The warning comes from statements :
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
All I want to know is what is causing this warning and what can I do to correct it if this is not the proper way to do things. Could I use any of static_cast
/ dynamic_cast
/ reinterpret_cast
here?
The exact warning is - cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4
.
Well
-Weverything
enables quite a lot of warnings some of them are known to throw unwanted warnings.Here your code fires the
cast-align
warning, that says explicitelyAnd it is the case here because the alignement for
struct addr
is only 2 whereas it is 4 forstruct addr_in
.But you (and the programmer for
getaddrinfo
...) know that the pointerp->ai_addr
already points to an actualstruct addr_in
, so the cast is valid.You can either:
-Wno-cast-align
after-Weverything
I must admit that I seldom use
-Weverything
for that reason, and only use-Wall
Alternatively, if you know that you only use CLang, you can use pragmas to explicetely turn the warning only on those lines:
To elaborate on the memcpy version. I thnk this is needed for ARM which cannot have misalligned data.
I created a struct that contains just the first two fields (I only needed port)
Then to get the port out, I used memcpy to move the data to the stack
And return the port
This answer is really related to getting the port on Arm
How do I cast sockaddr pointer to sockaddr_in on Arm
The powers that be think that to be the same question as this one, however I dont want to ignore warnings. Experience has taught me that is a bad idea.
TLDR: This warning doesn't indicate an error in your code, but you can avoid it by using a poper c++
reinterpret_cast
(thanks to @Kurt Stutsman).Explanation:
Reason for the warning:
sockaddr
consists of a unsigned short (usually 16 bit) and a char array, so its alignment requirement is 2.sockaddr_in
contains (among other things) astruct in_addr
which has an alignment requirement of 4 which in turn meanssockaddr_in
also must be aligned to a 4 Byte boundary.For that reason, casting an arbitrary
sockaddr*
to ansockaddr_in*
changes the alignment requirement, and accessing the object via the new pointer would even violate aliasing rules and result in undefined behavior.Why you can ignore it:
In your case, the object,
p->ai_addr
is pointing to, most likely is asockaddr_in
orsockaddr_in6
object anyway (as determined by checkingai_family
) and so the operation is safe. However you compiler doesn't know that and produces a warning.It is essentially the same thing as using a
static_cast
to cast a pointer to a base class to a pointer to a derived class - it is unsafe in the general case, but if you know the correct dynamic type extrinsically, it is well defined.Solution:
I don't know a clean way around this (other than suppress the warning), which is not unusual with warnings enabled by-Weverything
. You could copy the object pointed to byp->ai_addr
byte by byte to an object of the appropriate type, but then you could (most likely) no longer useaddr
the same way as before, as it would now point to a different (e.g. local) variable.-Weverything
isn't something I would use for my usual builds anyway, because it adds far too much noise, but if you want to keep it, @Kurt Stutsman mentioned a good solution in the comments:clang++ (g++ doesn't emit a warning in any case) doesn't emit a warning, if you use a
reinterpret_cast
instead of the c style cast (which you shouldn't use anyway), although both have (in this case) exactly the same functionality. Maybe becausereinterpret_cast
explicitly tells the compiler: "Trust me, I know, what I'm doing" .On a side Note: In c++ code you don't need the
struct
keywords.