假设在if语句中不会发生签名溢出

时间:2013-08-29 21:46:56

标签: c++ qt g++

为什么会出现此警告?如果我检查边界,这不是一个真正的假设。以及如何解决?

如果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);

4 个答案:

答案 0 :(得分: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的声明;这取决于你以后是否使用它。但是如果你按照我建议的方式简化代码,它应该以相同的方式工作更容易阅读和理解。

如果您收到编译器发出的警告消息,那么您的目标不应仅仅是让消息消失;它应该是向下钻取并找出编译器警告你的内容,以及你的代码导致该问题的原因。

您比我更了解此代码的上下文。如果您查看修订版本,您可能会发现它更清楚地表达了意图。

答案 1 :(得分:5)

从此GCC resource

  

-Wstrict溢

     

-Wstrict溢出= N

     

此选项仅在-fstrict-overflow处于活动状态时处于活动状态。它会警告编译器根据没有发生签名溢出的假设进行优化的情况。请注意,它不会警告代码可能溢出的所有情况:它只会警告编译器实现某些优化的情况。因此,此警告取决于优化级别。

     

如果所涉及的变量的值实际上发生溢出,那么假定未发生签名溢出的优化是完全安全的。因此,此警告很容易产生误报:对代码实际上不是问题的警告。为了帮助关注重要问题,定义了几个警告级别。在估计循环所需的迭代次数时,不会发出使用未定义的有符号溢出的警告,特别是在确定是否将执行循环时。


  

-Wstrict溢出= 1

     

警告有疑问且容易避免的案件。例如,使用-fstrict-overflow,编译器简化了x + 1&gt; x到1. -Wall启用此级别的-Wstrict-overflow;更高级别不是,必须明确要求。

     

-Wstrict溢出= 2

     

还警告其他将比较简化为常数的情况。例如:abs(x)&gt; = 0.这只能在-fstrict-overflow有效时简化,因为abs(INT_MIN)溢出到INT_MIN,小于零。 -Wstrict-overflow(没有级别)与-Wstrict-overflow = 2相同。

     

-Wstrict溢出= 3

     

还警告其他简化比较的情况。例如:x + 1&gt;将1简化为x> 1。 0

     

-Wstrict溢出= 4

     

还警告上述案例未涵盖的其他简化。例如:(x * 10)/ 5简化为x * 2.

     

-Wstrict溢出= 5

     

还警告编译器减少比较中涉及的常量的大小的情况。例如:x + 2&gt; y被简化为x + 1> = y。这仅在最高警告级别报告,因为此简化适用于许多比较,因此此警告级别会产生大量误报。

答案 2 :(得分:1)

解决方案是将我的整数更改为无符号整数:

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

答案 3 :(得分:0)

我刚刚在比较中解决了一个类似的问题,该问题适用于 x86 但不适用于 arm(优化级别 O2): 我用 (x-right<0) 替换了 (x

static inline bool shape_int_rectangle_contains ( 
    const shape_int_rectangle_t *this_, int32_t x, int32_t y )
{
    bool result;
    const int32_t right = (*this_).left + (*this_).width;
    const int32_t bottom = (*this_).top + (*this_).height;
    /*
     * warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true [-Wstrict-overflow]
     *
     * result = ( x >= (*this_).left )&&( y >= (*this_).top )&&( x < right )&&( y < bottom );
     *
     * fix:
     */
    result = ( x-(*this_).left >= 0 )&&( y-(*this_).top >= 0 )&&( x-right < 0 )&&( y-bottom < 0 );
    return result;
}