Вопрос по qt, c++, g++ – предполагая, что переполнение со знаком не происходит в операторе if

1

Почему появляется это предупреждение? Это не совсем предположение, если я проверю границы. И как исправить?

Еслиnum_actions_to_skip установлен на 1, вместо 2 ошибка исчезнет.

Спасибо

error: assuming signed overflow does not occur when assuming that (X - c) <= X is always true [-Werror=strict-overflow]
cc1plus: all warnings being treated as errors

Наif (loc >= 0 && loc < action_list.count()) {

const QList<QAction *> &action_list = tool_menu->actions();
static const int num_actions_to_skip = 2;
const int loc = action_list.count() - num_actions_to_skip;
if (loc >= 0 && loc < action_list.count()) {
    tool_menu->insertAction(action_list.at(loc),
                            action);
}

Началось с

Q_ASSERT_X(i >= 0 && i < p.size()

в qlist.h: 454, который выполняет ту же проверку, а также выдает эту ошибку, просто

tool_menu->insertAction(action_list.at(action_list.count() - 2),
                                action);
count без знака я предполагаю. Yakk - Adam Nevraumont
@Yakk, нет, size () и count () из Qt простоint. Alexis Wilke
По крайней мере, это указывает на то, что логика вашего кода немного сомнительна! Вы по сути делаc = a - b; if (c < a) .... Oliver Charlesworth

Ваш Ответ

3   ответа
7

Вам просто нужно переосмыслить свою логику.

static const int num_actions_to_skip = 2;
const int loc = action_list.count() - num_actions_to_skip;
if (loc >= 0 && loc < action_list.count()) {
    // ...
}

По всей видимостиaction_list.count() является постоянным значением (по крайней мере, оно не изменится при выполнении этого кода), и компилятор может это выяснить.

Давайте немного упростим это, заменивnum_actions_to_skip по2, уменьшаяaction_list.count() вcount, Затем мы можем повторно выразитьloc какcount - 2.

Твойif состояние становится:

if (count - 2 >= 0 && count - 2 < count)

что эквивалентно (при условии, что, как сказано в предупреждении компилятора, переполнения не происходит):

if (count >= 2 && -2 < 0)

Вторая половина этого,-2 > 0 Очевидно, это правда, так что вы можете спокойно отбросить его, что оставляет нас с

if (count >= 2)

Если заменить первоначальные термины, это дает нам:

static const int num_actions_to_skip = 2;
// const int loc = action_list.count() - num_actions_to_skip;
if (action_list.count() >= num_actions_to_skip) {
    // ...
}

Компилятор предупредил вас, что он выполняет оптимизацию, которая может быть недопустимой, если есть целочисленное переполнение (разрешается предполагать, что переполнения нет, потому что если есть поведение, неопределено). Было достаточно любезно предупредить вас об этом - что вам повезло, потому что оно указывало на то, что ваш код выполняет то, что ему не нужно.

Я не знаю, нужно ли вам сохранять декларациюloc; это зависит от того, используете ли вы его позже. Но если вы упростите код так, как я предложил, он должен работать так жеа также будет легче читать и понимать.

Если вы получите предупреждающее сообщение от компилятора, ваша цель должна состоять не только в том, чтобы сообщение исчезло; это должно быть детализировать и выяснить, о чем вас предупреждает компилятор, и помимо этого, почему ваш код вызывает эту проблему.

Вы знаете контекст этого кода лучше, чем я. Если вы посмотрите на пересмотренную версию, вы можете обнаружить, что она выражает намерение более четко.

Я знаю, что большая часть этого очевидна, я надеялся, что компилятор тоже так подумает и перестанет жаловаться. Как говорят мои более поздние правки, исходная проблема заключалась в строке кода Qt, которую я попытался прекратить с помощью явного кода в исходном посте. Спасибо за вклад clark
@Yakk: Да, учитывая, чтоcount без знака, ты прав. Но я думаю, что ОПнамерение должен был проверить этоcount >= 2, (Трудно сказать без контекста.) Keith Thompson
неправильно истолковано Обратите внимание, чтоint(count - 2) >= 0 это район отcount - 2 >=0 - нет (определенного) способаint Произведено из неподписанного может быть отрицательным, так что этот пункт тоже умирает. Yakk - Adam Nevraumont
2

Решением было заменить мои целые на беззнаковые:

const QList<QAction *> &action_list = tool_menu->actions();
static const unsigned int num_actions_to_skip = 2;
const unsigned int pos = action_list.count() - num_actions_to_skip;
assert(pos >= 0);
tool_menu->insertAction(action_list.at(pos),
                        action);
Эх, нет Это не решение. Это избавляет от предупреждения, потому что переполнение на unsigned int хорошо определено. Еслиcount==1pos по-прежнему> = 0. Это всегда так, в конце концов это не подписано. Но без знака (1-2)UNIT_MAX-1, очень большой.at(pos) не удастся. MSalters
Иassert(pos >= 0) не полезно ... Alexis Wilke
5

GCC ресурс:

-Wstrict-перелива

-Wstrict-Переполнение = п

Эта опция активна только когда активен -fstrict-overflow. Он предупреждает о случаях, когда компилятор оптимизирует на основании предположения, что переполнение со знаком не происходит. Обратите внимание, что он не предупреждает о всех случаях переполнения кода: он предупреждает только о случаях, когда компилятор реализует некоторую оптимизацию. Таким образом, это предупреждение зависит от уровня оптимизации.

Оптимизация, предполагающая, что переполнение со знаком не происходит, совершенно безопасно, если значения задействованных переменных таковы, что переполнение фактически никогда не происходит. Поэтому это предупреждение может легко дать ложное срабатывание: предупреждение о коде, который на самом деле не является проблемой. Чтобы помочь сосредоточиться на важных вопросах, определены несколько уровней предупреждений. Предупреждения об использовании неопределенного переполнения со знаком при оценке количества итераций, требуемых циклом, не выдаются, в частности, при определении, будет ли цикл выполняться вообще.

-Wstrict-Переполнение = 1

Предупреждать о случаях, которые являются сомнительными и легко избежать. Например, с -fstrict-overflow компилятор упрощает x + 1> x до 1. Этот уровень -Wstrict-overflow включается -Wall; более высокие уровни не являются и должны быть явно запрошены.

-Wstrict-Переполнение = 2

Также предупредите о других случаях, когда сравнение упрощается до константы. Например: abs (x)> = 0. Это может быть упрощено, только если действует -fstrict-overflow, поскольку abs (INT_MIN) переполняется до INT_MIN, который меньше нуля. -Wstrict-overflow (без уровня) аналогично -Wstrict-overflow = 2.

-Wstrict-Переполнение = 3

Также предупредите о других случаях, когда сравнение упрощено. Например: x + 1> 1 упрощается до x> 0.

-Wstrict-Переполнение = 4

Также предупреждаем о других упрощениях, не указанных выше. Например: (x * 10) / 5 упрощается до x * 2.

-Wstrict-Переполнение = 5

Также предупредите о случаях, когда компилятор уменьшает величину константы, участвующей в сравнении. Например: x + 2> y упрощается до x + 1> = y. Об этом сообщается только на самом высоком уровне предупреждений, поскольку это упрощение применимо ко многим сравнениям, поэтому этот уровень предупреждений дает очень большое количество ложных срабатываний.

@ foxrider67: Нет, компилятор не собирается "оптимизировать"int чтобыunsigned int, Значения, с которыми вы работаете, являются целыми числами; меняя их наdouble это не ответ. Вы должны изменить свою логику (я недостаточно изучил это, чтобы знать, как). Keith Thompson
Я изменил тип данных на qreal (double), и предупреждение исчезло (больше не int), возможно, компилятор оптимизировал int до unsigned int. clark

Похожие вопросы