我的代码中有这样的表达式:
QByteArray idx0 = ...
unsigned short ushortIdx0;
if ( idx0.size() >= sizeof(ushortIdx0) ) {
// Do something
}
但是我收到了警告:
警告:有符号和无符号整数表达式之间的比较[-Wsign-compare]
if ( idx0.size() >= sizeof(ushortIdx0) ) { ~~~~~~~~~~~~^~~~~~~~~~
为什么size()
的QByteArray
被归还为int
而不是unsigned int
?我怎样才能安全地摆脱这个警告?
有些人认为,几年前将unsigned
类型引入C是一个坏主意。这些类型发现自己被引入到C ++中,它们深深地嵌入到C ++标准库和操作符返回类型中。
是的,按照标准,sizeof
必须返回unsigned
类型。
Qt开发人员采用现代的思想认为unsigned
类型是一个坏主意,并且倾向于使size
的返回类型成为signed
类型。就个人而言,我发现它特殊。
要解决,你可以(i)接受警告,(ii)在功能期间关闭它,或者(iii)写下像
(std::size_t)idx0.size() >= sizeof(ushortIdx0)
以清晰为代价。
为什么QByteArray的size()以int而不是unsigned int的形式返回?
我真的不知道为什么Qt为size()
选择了签名回报。但是,有充分的理由使用signed而不是unsigned。
unsigned size()
悲惨失败的一个臭名昭着的例子是这个看起来很无辜的循环:
for (int i = 0; i < some_container.size() - 1; ++i) {
do_somehting(some_container[i] , some_container[i+1] );
}
将循环体操作在两个元素上并不常见,在这种情况下,它似乎只是迭代到some_container.size() - 1
的有效选择。
但是,如果容器是空的,some_container.size() - 1
将默默地(无符号溢出被很好地定义)转为无符号类型的最大值。因此,不是避免越界访问,而是导致你可以获得的最大越界。
请注意,此问题有一些简单的解决方法,但如果size()
确实返回了有符号值,那么首先不需要修复问题。
因为在Qt容器中(例如:QByteArray,QVector,...),有些函数可以返回负数,例如:indexOf,lastIndexOf,contains,...有些可以接受负数,例如:mid,... ;因此,为了与类兼容或甚至框架兼容,开发人员使用signed类型(int)。
您可以使用标准c ++强制转换:
if ( static_cast<size_t>(idx0.size()) >= sizeof(ushortIdx0) )
原因是问题的重复部分,但类型不匹配的解决方案是一个有待解决的问题。对于你正在进行的那种比较,将它们分解出来可能是有用的,因为它们具有一定的可重用含义:
template <typename T> bool fitsIn(const QByteArray &a) {
return static_cast<int>(sizeof(T)) <= a.size();
}
template <typename T> bool fitsIn(T, const QByteArray &a) {
return fitsIn<T>(a);
}
if (fitsIn(ushortIdx0, idx0)) ...
希望你只有几种这样的比较,并且最有意义的是干(不要重复自己)而不是使用专用于任务的复制品 - 使用专用于任务的函数 - 这些函数也表达了原来的比较。然后,很容易集中处理您可能希望处理的任何角落情况,即当sizeof(T) > INT_MAX
时。
另一种方法是定义一个新类型来包装size_t
并使其适应您需要使用它的类型:
class size_of {
size_t val;
template <typename T> static typename std::enable_if<std::is_signed<T>::value, size_t>::type fromSigned(T sVal) {
return (sVal > 0) ? static_cast<size_t>(sVal) : 0;
}
public:
template <typename T, typename U = std::enable_if<std::is_scalar<T>::value>::type>
size_of(const T&) : val(sizeof(T)) {}
size_of(const QByteArray &a) : val(fromSigned(a.size())) {}
...
bool operator>=(size_of o) const { return value >= o.value; }
};
if (size_of(idx0) >= size_of(ushortIdx0)) ...
这将在概念上扩展sizeof
并专门用于比较,而不是其他任何东西。