代码之家  ›  专栏  ›  技术社区  ›  AaronD

这是什么意思?

  •  1
  • AaronD  · 技术社区  · 7 年前

    最小应用程序:

    测试项目.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
    

    MCP.CPP:

    #include <mainwindow.h>
    #include <QApplication>
    
    int main(int argc, char* argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    主窗口:

    #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
    

    主窗口: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 没有。

    This question 有道理,因为这是有条件的,但我没有得到有条件的。我要把它放到函数本身上。

    我想使用更具攻击性的优化,但如果可以的话,仍然可以进行干净的编译。有什么奇怪的事吗 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 回复  |  直到 7 年前
        1
  •  1
  •   LoPiTaL    7 年前

    警告告诉您编译器不会检查子分数的结果是否为负数。

    为什么这在这一行很重要?

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

    因为您正在索引一个数组(实际上使用了一个指针变量,来自 data() 函数,它返回 T* )使用减法运算的结果,该运算可能会产生负数,这通常是不需要的。

    当您将该子除法移到一个新的变量时,编译器会看到您正在用 int 变量,而不是减法的结果,因此如果传递的变量为负或不为负,则不再发出警告。


    关于您的评论,您正在使用缓存数据 resize 功能。我不太确定为什么会发生这种情况,但我想这可能与 -O3 编译器启用以下标志:

    -finline-functions 
    

    http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html 了解更多详细信息。

    此标志启用所有内联函数优化。由于您使用的是所有模板化的类,编译器可能会内联所有相关的函数,缓存一些结果,并在某个地方优化有符号溢出。可能在 if 句中 调整大小 功能:

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

    但这只是一个猜测。