Why size of QByteArray is `int` rather than `unsig

2019-07-06 16:18发布

I have such expressions in my code:

QByteArray idx0 = ...

unsigned short ushortIdx0;

if ( idx0.size() >= sizeof(ushortIdx0) ) {
    // Do something
}

But I'm getting the warning:

warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

if ( idx0.size() >= sizeof(ushortIdx0) ) {
              ~~~~~~~~~~~~^~~~~~~~~~

Why size() of QByteArray is returned as int rather than unsigned int? How can I get rid of this warning safely?

4条回答
\"骚年 ilove
2楼-- · 2019-07-06 16:23

The reason why is a duplicate part of the question, but the solution to the type mismatch is a valid problem to solve. For the comparisons of the kind you're doing, it'd probably be useful to factor them out, as they have a certain reusable meaning:

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)) ...

Hopefully you'll have just a few kinds of such comparisons, and it'd make most sense to DRY (do not repeat yourself) and instead of a copypasta of casts, use functions dedicated to the task - functions that also express the intent of the original comparison. It then becomes easy to centralize handling of any corner cases you might wish to handle, i.e. when sizeof(T) > INT_MAX.

Another approach would be to define a new type to wrap size_t and adapt it to the types you need to use it with:

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)) ...

This would conceptually extend sizeof and specialize it for comparison(s) and nothing else.

查看更多
干净又极端
3楼-- · 2019-07-06 16:26

Some folk feel that the introduction of unsigned types into C all those years ago was a bad idea. Such types found themselves introduced into C++, where they are deeply embedded in the C++ Standard Library and operator return types.

Yes, sizeof must, by the standard, return an unsigned type.

The Qt developers adopt the modern thinking that the unsigned types were a bad idea, and favour instead making the return type of size a signed type. Personally I find it idiosyncratic.

To solve, you could (i) live with the warning, (ii) switch it off for the duration of the function, or (iii) write something like

(std::size_t)idx0.size() >= sizeof(ushortIdx0)

at the expense of clarity.

查看更多
▲ chillily
4楼-- · 2019-07-06 16:33

Because in Qt containers (like: QByteArray, QVector, ...) there are functions which can return a negative number, like: indexOf, lastIndexOf, contains, ... and some can accept negative numbers, like: mid, ...; So to be class-compatible or even framework-compatibe, developers use a signed type (int).

You can use standard c++ casting:

if ( static_cast<size_t>(idx0.size()) >= sizeof(ushortIdx0) )
查看更多
兄弟一词,经得起流年.
5楼-- · 2019-07-06 16:41

Why size() of QByteArray is returned as int rather than unsigned int?

I literally have no idea why Qt chose a signed return for size(). However, there are good reasons to use a signed instead of an unsigned.

One infamous example where a unsigned size() fails miserably is this quite innocent looking loop:

for (int i = 0; i < some_container.size() - 1; ++i) {
     do_somehting(some_container[i] , some_container[i+1] );
}

Its not too uncommon to make the loop body operate on two elements and in that case its seems to be a valid choice to iterate only till some_container.size() - 1.

However, if the container is empty some_container.size() - 1 will silently (unsigned overflow is well defined) turn into the biggest value for the unsigned type. Hence, instead of avoiding the out-of-bounds access it leads to the maximum out of bounds you can get.

Note that there are easy fixes for this problem, but if size() does return a signed value, then there is no issue that needs to be fixed in the first place.

查看更多
登录 后发表回答