簡體   English   中英

為什么clang中的-O2或更高優化會破壞這段代碼?

[英]Why does -O2 or greater optimization in clang break this code?

我在網站上檢查了類似的問題,但我找不到符合我的情況的任何內容。 這是我試圖運行的代碼(需要C ++ 14):

#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 ,它確實如此:

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 X上使用最新Apple LLVM version 7.3.0 (clang-703.0.31) clang --versionApple LLVM version 7.3.0 (clang-703.0.31)

奇怪的是,我的代碼不包含任何奇怪的自編循環,未定義的行為,或類似的東西,它幾乎只是標准的庫調用,所以優化打破它是非常奇怪的。

有任何想法嗎?

PS:我沒有在其他編譯器上嘗試過,但我很樂意。 我將用這些結果更新問題。

bool started未初始化。 如果將其初始化為false ,則它適用於-O2

實例

您可以使用Undefined行為清理程序找到這樣的錯誤:

$ g++ -std=c++14 -O2 -g -fsanitize=undefined -fno-omit-frame-pointer main.cpp && ./a.out

main.cpp:18:9: runtime error: load of value 106, which is not a valid value for type 'bool'

錯誤在你的構造函數中:

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

你忘了初始化started 當您調用start()時,這會觸發未定義的行為。

沒有我方便訪問的clang版本會診斷出這個錯誤,但是GCC版本5和6(在Linux上 - 我的Mac上沒有GCC)將會:

$ 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);
                    ^~~~~

(我的Xcode副本似乎有點過時, Apple LLVM version 7.0.2 (clang-700.1.81) ;它不會改變程序在-O2的行為。 你的 clang可能會診斷出這個如果您打開警告,則會出錯。)

(我已向GCC提交了關於診斷中IR gobbledygook的錯誤報告 。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM