错误的 `-Wsign-conversion` 错误与 `ntohs(...)` 在 ARM 上?
Erroneous `-Wsign-conversion` Error With `ntohs(...)` on ARM?
这里是一个 SSCCE,显示了我的代码的简化版本,但仍然可以做一些有用的事情:
//Compile with -O3 -Wsign-conversion
#include <arpa/inet.h>
#include <string>
void _extract_ip_port(struct sockaddr const* addr, std::string* host,unsigned short* port) {
if (addr->sa_family == AF_INET) { //IPv4
struct sockaddr_in const* ipv4 = reinterpret_cast<struct sockaddr_in const*>(addr);
char temp[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ipv4->sin_addr, temp, INET_ADDRSTRLEN);
*host = temp;
*port = ntohs(ipv4->sin_port); //<---- ##### WARNING HERE #####
} else { //IPv6
struct sockaddr_in6 const* ipv6 = reinterpret_cast<struct sockaddr_in6 const*>(addr);
char temp[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6->sin6_addr, temp, INET6_ADDRSTRLEN);
*host = temp;
*port = ntohs(ipv6->sin6_port); //<---- ##### WARNING HERE #####
}
}
问题是对 ntohs(...)
的调用会产生如下内容:
<file>:<line>:<char>: warning: conversion to "unsigned int" from "int" may change the sign
of the result [-Wsign-conversion]
*port = ntohs(ipv6->sin6_port); //<---- ##### WARNING HERE #####
^
正如您从上面链接的文档中看到的那样,ntohs(...)
有一个重载,returns 是一个无符号短整型。由于 port
、ipv4->sin_port
和 ipv6->sin6_port
都是这样,因此不应出现此警告。所以我的问题是:发生了什么事?
g++版本为5.3.0-3ubuntu1~14.04
,系统基于ARMv7。我还没有能够在 x86 或 x86-64 上重现它,所以我也标记它 arm。
这似乎是与 语句表达式 和 C++ 相关的问题。这是一个展示行为的简单程序。
int main(void)
{
unsigned int port =
(__extension__ ({ unsigned short int __bsx =
(unsigned short int) (0x8345u);
((unsigned short int)((((__bsx) >> 8) & 0xffu) |
(((__bsx) & 0xffu) << 8))); }));
return (int)port;
}
我将其命名为 'bar.c',这些会给出警告,
gcc -O3 -Wsign-conversion-x c++ baz.c
arm-linux-gnueabi-gcc -O3 -Wsign-conversion -x c++ baz.c
这些都没有,
gcc -O3 -Wsign-conversion bar.c
arm-linux-gnueabi-gcc -O3 -Wsign-conversion baz.c
此外,如果去掉语句表达式,则任何语言都没有警告。例如,
int main(void)
{
unsigned int port = 0x8345u;
((unsigned short int)(((port) >> 8) & 0xffu) | (((port) & 0xffu) << 8));
return (int)port;
}
So my question: what's going on?
将 语句表达式 与 C++ 组合时存在一些问题。参见documentation。特别是,
These considerations mean that it is probably a bad idea to use statement expressions of this form in header files that are designed to work with C++. (Note that some versions of the GNU C Library contained header files using statement expressions that lead to precisely this bug.)
所以要么使用 'C' 编译,要么接受警告。这可能是 header 中的 bug 或 g++。它与 ARM CPU 无关;你只是得到一个不同的 header 文件,它显示了为 ARM.
编译时的问题
相关:Endian conversion in C++, in other words __builtin_bswap16
.
这里是一个 SSCCE,显示了我的代码的简化版本,但仍然可以做一些有用的事情:
//Compile with -O3 -Wsign-conversion
#include <arpa/inet.h>
#include <string>
void _extract_ip_port(struct sockaddr const* addr, std::string* host,unsigned short* port) {
if (addr->sa_family == AF_INET) { //IPv4
struct sockaddr_in const* ipv4 = reinterpret_cast<struct sockaddr_in const*>(addr);
char temp[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ipv4->sin_addr, temp, INET_ADDRSTRLEN);
*host = temp;
*port = ntohs(ipv4->sin_port); //<---- ##### WARNING HERE #####
} else { //IPv6
struct sockaddr_in6 const* ipv6 = reinterpret_cast<struct sockaddr_in6 const*>(addr);
char temp[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6->sin6_addr, temp, INET6_ADDRSTRLEN);
*host = temp;
*port = ntohs(ipv6->sin6_port); //<---- ##### WARNING HERE #####
}
}
问题是对 ntohs(...)
的调用会产生如下内容:
<file>:<line>:<char>: warning: conversion to "unsigned int" from "int" may change the sign
of the result [-Wsign-conversion]
*port = ntohs(ipv6->sin6_port); //<---- ##### WARNING HERE #####
^
正如您从上面链接的文档中看到的那样,ntohs(...)
有一个重载,returns 是一个无符号短整型。由于 port
、ipv4->sin_port
和 ipv6->sin6_port
都是这样,因此不应出现此警告。所以我的问题是:发生了什么事?
g++版本为5.3.0-3ubuntu1~14.04
,系统基于ARMv7。我还没有能够在 x86 或 x86-64 上重现它,所以我也标记它 arm。
这似乎是与 语句表达式 和 C++ 相关的问题。这是一个展示行为的简单程序。
int main(void)
{
unsigned int port =
(__extension__ ({ unsigned short int __bsx =
(unsigned short int) (0x8345u);
((unsigned short int)((((__bsx) >> 8) & 0xffu) |
(((__bsx) & 0xffu) << 8))); }));
return (int)port;
}
我将其命名为 'bar.c',这些会给出警告,
gcc -O3 -Wsign-conversion-x c++ baz.c
arm-linux-gnueabi-gcc -O3 -Wsign-conversion -x c++ baz.c
这些都没有,
gcc -O3 -Wsign-conversion bar.c
arm-linux-gnueabi-gcc -O3 -Wsign-conversion baz.c
此外,如果去掉语句表达式,则任何语言都没有警告。例如,
int main(void)
{
unsigned int port = 0x8345u;
((unsigned short int)(((port) >> 8) & 0xffu) | (((port) & 0xffu) << 8));
return (int)port;
}
So my question: what's going on?
将 语句表达式 与 C++ 组合时存在一些问题。参见documentation。特别是,
These considerations mean that it is probably a bad idea to use statement expressions of this form in header files that are designed to work with C++. (Note that some versions of the GNU C Library contained header files using statement expressions that lead to precisely this bug.)
所以要么使用 'C' 编译,要么接受警告。这可能是 header 中的 bug 或 g++。它与 ARM CPU 无关;你只是得到一个不同的 header 文件,它显示了为 ARM.
编译时的问题相关:Endian conversion in C++, in other words __builtin_bswap16
.