为什么 QByteArray 的大小是 `int` 而不是 `unsigned int`
Why size of QByteArray is `int` rather than `unsigned int`
我的代码中有这样的表达式:
QByteArray idx0 = ...
unsigned short ushortIdx0;
if ( idx0.size() >= sizeof(ushortIdx0) ) {
// Do something
}
但我收到警告:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if ( idx0.size() >= sizeof(ushortIdx0) ) {
~~~~~~~~~~~~^~~~~~~~~~
为什么 QByteArray
的 size()
返回为 int
而不是 unsigned int
?我怎样才能安全地摆脱这个警告?
一些人认为,多年前将 unsigned
类型引入 C 是一个坏主意。这些类型发现自己被引入到 C++ 中,在那里它们深深地嵌入到 C++ 标准库和运算符 return 类型中。
是的,sizeof
按照标准,return 必须是 unsigned
类型。
Qt 开发人员采用了现代思想,即 unsigned
类型是一个坏主意,并倾向于将 size
的 return 类型改为 signed
类型。我个人觉得它很特别。
要解决这个问题,您可以 (i) 接受警告,(ii) 在函数运行期间将其关闭,或者 (iii) 编写类似
的内容
(std::size_t)idx0.size() >= sizeof(ushortIdx0)
以牺牲清晰度为代价。
Why size() of QByteArray is returned as int rather than unsigned int?
我真的不知道为什么 Qt 为 size()
选择了带符号的 return。但是,有充分的理由使用有符号而不是无符号。
一个臭名昭著的 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()
确实 return 有符号值,那么首先就没有问题需要修复。
因为在 Qt 容器中(如:QByteArray、QVector,...)有些函数可以 return 一个负数,如:indexOf、lastIndexOf、contains,...有些函数可以接受负数数字,例如:mid,...;因此,为了 class 兼容甚至框架兼容,开发人员使用签名类型 (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)) ...
希望你只会有几种这样的比较,DRY(不要重复你自己)最有意义,而不是复制粘贴,使用专用于任务的函数 - 函数也表达了最初比较的意图。然后可以轻松集中处理您可能希望处理的任何极端情况,即 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
并将其专门用于比较而不是其他。
我的代码中有这样的表达式:
QByteArray idx0 = ...
unsigned short ushortIdx0;
if ( idx0.size() >= sizeof(ushortIdx0) ) {
// Do something
}
但我收到警告:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if ( idx0.size() >= sizeof(ushortIdx0) ) { ~~~~~~~~~~~~^~~~~~~~~~
为什么 QByteArray
的 size()
返回为 int
而不是 unsigned int
?我怎样才能安全地摆脱这个警告?
一些人认为,多年前将 unsigned
类型引入 C 是一个坏主意。这些类型发现自己被引入到 C++ 中,在那里它们深深地嵌入到 C++ 标准库和运算符 return 类型中。
是的,sizeof
按照标准,return 必须是 unsigned
类型。
Qt 开发人员采用了现代思想,即 unsigned
类型是一个坏主意,并倾向于将 size
的 return 类型改为 signed
类型。我个人觉得它很特别。
要解决这个问题,您可以 (i) 接受警告,(ii) 在函数运行期间将其关闭,或者 (iii) 编写类似
的内容(std::size_t)idx0.size() >= sizeof(ushortIdx0)
以牺牲清晰度为代价。
Why size() of QByteArray is returned as int rather than unsigned int?
我真的不知道为什么 Qt 为 size()
选择了带符号的 return。但是,有充分的理由使用有符号而不是无符号。
一个臭名昭著的 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()
确实 return 有符号值,那么首先就没有问题需要修复。
因为在 Qt 容器中(如:QByteArray、QVector,...)有些函数可以 return 一个负数,如:indexOf、lastIndexOf、contains,...有些函数可以接受负数数字,例如:mid,...;因此,为了 class 兼容甚至框架兼容,开发人员使用签名类型 (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)) ...
希望你只会有几种这样的比较,DRY(不要重复你自己)最有意义,而不是复制粘贴,使用专用于任务的函数 - 函数也表达了最初比较的意图。然后可以轻松集中处理您可能希望处理的任何极端情况,即 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
并将其专门用于比较而不是其他。