Почему размер QByteArray является `int`, а не` unsigned int` - PullRequest
0 голосов
/ 03 сентября 2018

В моем коде есть такие выражения:

QByteArray idx0 = ...

unsigned short ushortIdx0;

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

Но я получаю предупреждение:

предупреждение: сравнение между целочисленными выражениями со знаком и без знака [-Wsign-compare]

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

Почему size() из QByteArray возвращается как int, а не unsigned int? Как мне безопасно избавиться от этого предупреждения?

Ответы [ 4 ]

0 голосов
/ 04 сентября 2018

Причина, по которой повторяется часть вопроса, но решение несоответствия типов является действительной проблемой, которую необходимо решить. Для сравнений, которые вы делаете, было бы полезно выделить их, поскольку они имеют определенное многократное значение:

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 и специализирует его для сравнения (ий) и ничего больше.

0 голосов
/ 03 сентября 2018

Почему size () QByteArray возвращается как int, а не как unsigned int?

Я буквально не знаю, почему Qt выбрал подписанное возвращение для size(). Однако есть веские причины использовать подписанный вместо неподписанного.

Один печально известный пример, когда 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() возвращает значение со знаком, то нет проблемы, которую нужно было бы исправить в первую очередь.

0 голосов
/ 03 сентября 2018

Поскольку в контейнерах Qt (например, QByteArray, QVector, ...) есть функции, которые могут возвращать отрицательное число, например: indexOf, lastIndexOf, содержит, ..., а некоторые могут принимать отрицательные числа, например: mid, ...; Поэтому, чтобы быть совместимыми с классами или даже совместимыми с фреймворком, разработчики используют подписанный тип (int).

Вы можете использовать стандартное приведение c ++:

if ( static_cast<size_t>(idx0.size()) >= sizeof(ushortIdx0) )
0 голосов
/ 03 сентября 2018

Некоторые люди считают, что введение unsigned типов в C много лет назад было плохой идеей. Такие типы появились в C ++, где они глубоко внедрены в стандартную библиотеку C ++ и возвращают операторы.

Да, sizeof по стандарту должно возвращать тип unsigned.

Разработчики Qt придерживаются современного мнения о том, что типы unsigned были плохой идеей, и предпочитают вместо этого сделать возвращаемый тип size a signed. Лично я нахожу это уникальным.

Чтобы решить, вы можете (i) жить с предупреждением, (ii) выключать его на время выполнения функции или (iii) писать что-то вроде

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

за счет ясности.

...