Что здесь означает [-Wstrict-overflow]? - PullRequest
0 голосов
/ 01 января 2019

Минимальное приложение:

TestProject.pro:

QT       += core gui widgets
CONFIG   += C++11

QMAKE_CXXFLAGS_RELEASE -= -O
QMAKE_CXXFLAGS_RELEASE -= -O0
QMAKE_CXXFLAGS_RELEASE -= -O1
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE *= -O3
QMAKE_CXXFLAGS_RELEASE -= -Os
QMAKE_CXXFLAGS_RELEASE -= -Ofast

TARGET   = TestProject
TEMPLATE = app

SOURCES += main.cpp\
           mainwindow.cpp

HEADERS += mainwindow.h

main.cpp:

#include <mainwindow.h>
#include <QApplication>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QObject>
#include <QStack>

class Other : public QObject
{
    Q_OBJECT
public:
    explicit Other(QObject* parent = 0);
    virtual ~Other();

    void test();

private:
    QStack<int> myStack;
};

//--------------------------------------------------------------------------------------------------

#include <QMainWindow>
#include <QPushButton>
#include <QTextEdit>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget* parent = 0);
    virtual ~MainWindow();
};

#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"

Other::Other(QObject* parent) :
    QObject(parent)
{}

Other::~Other()
{}

void Other::test()  //warning on this line
{
    myStack.pop();  //but not when this line is commented
}

//--------------------------------------------------------------------------------------------------

MainWindow::MainWindow(QWidget* parent) :
    QMainWindow(parent)
{
    (new Other(this))->test();
}

MainWindow::~MainWindow()
{}


Компиляция с g++ -O3 -Wall дает следующее предупреждение:

...TestProject/mainwindow.cpp:10: warning: assuming signed overflow does not occur when assuming that (X - c) <= X is always true [-Wstrict-overflow]
 void Other::test()  //warning on this line
      ^

Компиляция с g++ -O2 -Wall не дает.

Этот вопрос имеет смысл, так как он для условного, ноЯ не получаю это по условию.Я получаю это на саму функцию.

Я бы хотел использовать более агрессивную оптимизацию, но все же скомпилировать, если смогу.Что-то странное происходит с QStack?


Обновление:

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

Я скопировал код из qstack.h и вставил его в свою собственную функцию, затем вызвал его вместо встроенного QStack::pop():

void Other::pop()  //warning on this line
{
    Q_ASSERT(!myStack.isEmpty());
    int t = myStack.data()[myStack.size() - 1];
            myStack.resize(myStack.size() - 1);
    return t;
}

Все еще есть предупреждение, но оно перешло к пользовательской функции pop().

Затем я немного поиграл с этим и обнаружил, что кэширование myStack.size() - 1 для операции resize убивает предупреждение, но только если оносделано перед извлечением data():

void Other::pop()  //no warning
{
    Q_ASSERT(!myStack.isEmpty());
    int size = myStack.size() - 1;
    int t = myStack.data()[myStack.size() - 1];
            myStack.resize(size);
    return t;
}

Использование кэшированного значения для обеих операций также без предупреждения.

Так что это один из, вероятно, нескольких способов избавиться от него, ноКто-нибудь знает, почему это происходит здесь?

1 Ответ

0 голосов
/ 24 января 2019

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

Почему это имеет значение в этой конкретной строке?

myStack.data()[myStack.size() - 1];

Потому что выиндексируют массив (фактически используя переменную-указатель, полученную из функции data(), которая возвращает T*), используя результат операции вычитания, что может привести к отрицательному числу, которое обычно является чем-то, что вы надеваете

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


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

-finline-functions 

См. http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html для получения дополнительной информации.

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

template <typename T>
void QVector<T>::resize(int asize)
{
    int newAlloc;
    const int oldAlloc = int(d->alloc);
    QArrayData::AllocationOptions opt;

    //Here, asize will be replaced with d->size - 1 after all the inlining.
    //So the compiler is assuming that d->size - 1 will not overflow, 
    //  because of undefined behaviour, 
    //  instead of thinking that it may wrap.
    if (asize > oldAlloc) { 
        newAlloc = asize;
        opt = QArrayData::Grow;
    } else {
        newAlloc = oldAlloc;
    }
    reallocData(asize, newAlloc, opt);
}

Но это всего лишь предположение.

...