首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么clang中的-O2或更大的优化会破坏这段代码?

为什么clang中的-O2或更大的优化会破坏这段代码?
EN

Stack Overflow用户
提问于 2016-08-06 14:28:07
回答 1查看 992关注 0票数 5

我在网站上检查了类似的问题,但是我在这里找不到与我的场景相匹配的东西。这是我要运行的代码(需要C++14):

代码语言:javascript
运行
复制
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;

class countdownTimer {
public:
    using duration_t = chrono::high_resolution_clock::duration;

    countdownTimer(duration_t duration) : duration{ duration }, paused{ true } {}

    countdownTimer(const countdownTimer&)               = default;
    countdownTimer(countdownTimer&&)                    = default;
    countdownTimer& operator=(countdownTimer&&)         = default;
    countdownTimer& operator=(const countdownTimer&)    = default;

    void start() noexcept {
        if (started) return;
        startTime = chrono::high_resolution_clock::now();
        endTime = startTime + duration;
        started = true;
        paused = false;
    }

    void pause() noexcept {
        if (paused || !started) return;
        pauseBegin = chrono::high_resolution_clock::now();
        paused = true;
    }

    void resume() noexcept {
        if (!paused || !started) return;
        auto pauseDuration = chrono::high_resolution_clock::now() - pauseBegin;
        startTime += pauseDuration;
        endTime += pauseDuration;
        paused = false;
    }

    double remainingSeconds() const noexcept {
        auto ret = double{ 0.0 };
        if (!started) ret = chrono::duration_cast<chrono::duration<double>>(duration).count();
        else if (paused) ret = chrono::duration_cast<chrono::duration<double>>(duration - (pauseBegin - startTime)).count();
        else ret = chrono::duration_cast<chrono::duration<double>>(duration - (chrono::high_resolution_clock::now() - startTime)).count();
        return (ret < 0.0) ? 0.0 : ret;
    }

    duration_t remainingTime() const noexcept {
        auto ret = duration_t{ 0ms };
        if (!started) ret = chrono::duration_cast<duration_t>(duration);
        else if (paused) ret = chrono::duration_cast<duration_t>(duration - (pauseBegin - startTime));
        else ret = chrono::duration_cast<duration_t>(duration - (chrono::high_resolution_clock::now() - startTime));
        return (ret < 0ms) ? 0ms : ret;
    }

    bool isPaused() const noexcept { return paused; }

    bool hasFinished() const noexcept { return remainingTime() == 0s; }

    void reset() noexcept {
        started = false;
        paused = true;
    }

private:
    chrono::high_resolution_clock::time_point startTime;
    chrono::high_resolution_clock::time_point endTime;
    chrono::high_resolution_clock::time_point pauseBegin;
    duration_t duration;
    bool paused;
    bool started;
};

int main() {
    countdownTimer timer(10s);
    timer.start();

    while (!timer.hasFinished()) {
        cout << timer.remainingSeconds() << endl;
        this_thread::sleep_for(1s);
    }
}

这是一个简单的倒计时类,我为我的一个项目写的。main()中的客户端代码是非常不言自明的,它应该将倒计时从10输出到0,然后退出程序。在没有优化或-O/-O1的情况下,它正是这样做的:

代码语言:javascript
运行
复制
10
8.99495
7.98992
6.9849
5.97981
4.9748
3.96973
2.9687
1.9677
0.966752
Program ended with exit code: 0

但是如果我加强对>=-O2的优化,程序就会一直输出10,并且永远运行。倒计时根本不起作用,只是停留在起始值上。

我在OS上使用最新的Xcode。clang --version说,Apple LLVM version 7.3.0 (clang-703.0.31)说。

奇怪的是,我的代码不包含任何奇怪的自写循环、未定义的行为或诸如此类的东西,它几乎只是标准库调用,所以优化破坏它是非常奇怪的。

有什么想法吗?

PS:我还没有在其他编译器上试过,但我马上就要试了。我会用这些结果更新问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-08-06 14:38:44

错误在构造函数中:

代码语言:javascript
运行
复制
 countdownTimer(duration_t duration)
 : duration{ duration }, paused{ true } {}

您忘记初始化started了。这会在调用start()时触发未定义的行为。

没有任何版本的clang可以方便地进行此错误诊断,但是GCC版本5和6(在Linux上-我不再在我的Mac上安装GCC )将:

代码语言:javascript
运行
复制
$ g++ -O2 -Wall -Wextra -std=c++14 test.cc
test.cc: In function ‘int main()’:
test.cc:18:13: warning: ‘*((void*)& timer +33)’ is used uninitialized in this function [-Wuninitialized]
         if (started) return;
             ^~~~~~~
test.cc:74:20: note: ‘*((void*)& timer +33)’ was declared here
     countdownTimer timer(10s);
                    ^~~~~

(使用Apple LLVM version 7.0.2 (clang-700.1.81),我的Xcode副本似乎有点过时了;它不会改变-O2程序的行为。如果打开警告,clang可能会诊断此错误。)

(我已经在诊断学中提交了一份关于IR的GCC的错误报告文件。)

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38805335

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档