亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

C+0x中的“while(1);”優化

C+0x中的“while(1);”優化

C++
SMILET 2019-07-10 14:46:44
C+0x中的“while(1);”優化我聽說和閱讀過C+0x允許編譯器為下面的片段打印“Hello”#include <iostream>int main() {   while(1)      ;   std::cout << "Hello" << std::endl;}這顯然與線程和優化功能有關。但在我看來,這會讓很多人感到驚訝。有人能很好地解釋為什么這是必要的嗎?作為參考,最近的C+0x草案指出6.5/5一個循環,在for語句的for init語句之外,不調用庫I/O函數,以及不訪問或修改易失性對象,并且不執行同步操作(1.10)或原子操作(第29條)可由實現假定終止。[注意:這是為了允許編譯器轉換-mdash;,例如刪除空循環,即使終止不能被證明。-尾注]編輯:這篇有見地的文章關于標準文本不幸的是,沒有使用“未定義的行為”這個詞。然而,每當標準說“編譯器可以假定P”時,這就意味著具有非-P屬性的程序具有未定義的語義。這是正確的,編譯器是否允許為上述程序打印“Bye”?有一個更有洞察力的線在這里,這是一個與C類似的變化,由GuyDoes開始上面的鏈接文章。在其他有用的事實中,它們提供了一個解決方案,似乎也適用于C+0x(更新:這將不再適用于n 3225-見下面!)endless:   goto endless;編譯器似乎不允許對其進行優化,因為它不是循環,而是跳轉。另一個人總結了C+0x和C201x的擬議更改通過編寫循環,程序員正在斷言任一循環具有可見行為(執行I/O、訪問易失性對象或執行同步或原子操作),或它最終會終止。如果我違反了這個假設,寫了一個沒有副作用的無限循環,我就是在欺騙編譯器,而我的程序的行為是沒有定義的。(如果我幸運的話,編譯器可能會警告我。)語言不提供(不再提供?)一種在沒有可見行為的情況下表示無限循環的方法。用n 3225更新3.1.2011:委員會將文本移至1.10/24并說該實現可能假定任何線程最終都將執行以下操作之一:終止,調用庫I/O函數,訪問或修改易失性對象,或執行同步操作或原子操作。這個goto特技威爾不繼續工作!
查看完整描述

3 回答

?
Cats萌萌

TA貢獻1805條經驗 獲得超9個贊

有人能很好地解釋為什么這是必要的嗎?

是的,Hans Boehm在N 1528:為什么無限循環的行為沒有定義?雖然這是WG14文件,但理由也適用于C+,該文件同時提到WG14和WG21:

正如N 1509正確指出的那樣,當前的草案本質上給出了6.8.5p6中無限循環的未定義行為。這樣做的一個主要問題是,它允許代碼在一個潛在的非終止循環中移動。例如,假設我們有以下循環,其中Count和Count 2是全局變量(或已獲取它們的地址),而p是局部變量,其地址尚未被接受:

for (p = q; p != 0; p = p -> next) {
    ++count;}for (p = q; p != 0; p = p -> next) {
    ++count2;}

這兩個循環能被合并替換為下面的循環嗎?

for (p = q; p != 0; p = p -> next) {
        ++count;
        ++count2;}

如果沒有6.8.5p6中對無限循環的特殊分配,這將是不允許的:如果第一個循環沒有因為q指向循環列表而終止,那么原始循環就不會寫到Count 2。因此,它可以與訪問或更新Count 2的另一個線程并行運行。對于轉換后的版本來說,這已經不再安全了,盡管存在無限循環,但它仍然可以訪問Count 2。因此,轉換可能會引入數據競爭。

在這種情況下,編譯器很難證明循環終止;它必須理解Q指向一個非循環列表,我認為這超出了大多數主流編譯器的能力,而且沒有完整的程序信息通常是不可能的。

非終止循環所施加的限制是對編譯器無法證明終止的終止循環的優化的限制,也是對實際非終止循環的優化的限制。前者比后者更常見,而優化往往更有趣。

顯然還有帶有整數循環變量的for-循環,編譯器很難證明終止,因此編譯器很難在沒有6.8.5p6的情況下重構循環。甚至像

for (i = 1; i != 15; i += 2)

for (i = 1; i <= 10; i += j)

似乎很難處理。(在前一種情況下,需要一些基本的數論來證明終止,在后一種情況下,我們需要了解j的可能值。對無符號整數的環繞可能會進一步使這種推理復雜化。)

這個問題似乎適用于幾乎所有的循環重構轉換,包括編譯器并行化和緩存優化轉換,這兩種轉換都很可能變得重要,而且對數值代碼通常也很重要。這似乎會變成一筆巨大的成本,以便能夠以最自然的方式編寫無限循環,特別是因為我們大多數人很少有意識地編寫無限循環。

C的一個主要區別是c11為控制常量表達式提供了一個異常。它與C+不同,并使您的具體示例在C11中得到了很好的定義。


查看完整回答
反對 回復 2019-07-10
?
牛魔王的故事

TA貢獻1830條經驗 獲得超3個贊

對我來說,有關的理由是:

這是為了允許編譯器轉換-mdash;,例如刪除空循環,即使終止不能被證明。

想必,這是因為機械地證明終止是,如果不能證明終止,就會妨礙編譯器進行有用的轉換,例如將非依賴操作從循環前移到后面,反之亦然,在一個線程中執行循環后操作,而在另一個線程中執行循環,等等。如果沒有這些轉換,則在等待一個線程完成所述循環時,循環可能會阻塞所有其他線程。(我松散地使用“線程”來表示任何形式的并行處理,包括單獨的VLIW指令流。)

編輯:愚蠢的例子:

while (complicated_condition()) {
    x = complicated_but_externally_invisible_operation(x);}complex_io_operation();cout << "Results:" << endl;cout << x << endl;

在這里,一個線程執行complex_io_operation而另一個則在循環中做所有復雜的計算。但是,如果沒有您引用的子句,編譯器必須證明兩件事才能進行優化:1)complex_io_operation()不依賴于循環的結果,和2)循環將終止..證明1)很容易,證明2)是停止的問題。使用該子句,它可能假定循環終止并獲得并行化勝利。

我還設想設計人員認為,在生產代碼中出現無限循環的情況非常罕見,通常是類似事件驅動的循環,以某種方式訪問I/O。因此,他們悲觀了罕見的情況(無限循環),而傾向于優化更常見的情況(非無限,但很難機械地證明為非無限循環)。

然而,這確實意味著,在學習示例時使用的無限循環將因此而受到影響,并將在初學者代碼中引起棘手的問題。我不能說這完全是件好事。

編輯:關于您現在鏈接的有洞察力的文章,我會說“編譯器可能假定程序的X”在邏輯上等同于“如果程序不滿足X,行為是未定義的”。我們可以如下所示:假設存在一個不滿足屬性X的程序,該程序的行為將在哪里定義?標準只定義假設屬性X為真的行為。盡管“標準”沒有明確聲明未定義的行為,但它通過省略聲明未對其進行定義。

考慮一個類似的論點:“編譯器可能假設變量x最多只在序列點之間分配一次”相當于“在序列點之間分配給x的次數超過一次”。


查看完整回答
反對 回復 2019-07-10
?
小怪獸愛吃肉

TA貢獻1852條經驗 獲得超1個贊

我認為正確的解釋來自您的編輯:空無限循環是未定義的行為。

我不認為這是特別直觀的行為,但這種解釋比另一種解釋更有意義,即編譯器被任意允許視而不見不調用UB的無限循環。

如果無限循環是ub,那就意味著非終止程序被認為沒有意義:根據C+0x,它們沒有語義學。

這也有一定的道理。它們是一個特例,許多副作用不再發生(例如,從沒有從main),許多編譯器優化由于必須保留無限循環而受到阻礙。例如,在循環中移動計算是完全有效的,如果循環沒有副作用,因為最終,計算將在任何情況下執行。但是,如果循環從未終止,那么我們就不能安全地重新排列整個循環的代碼,因為我們強權只需在程序掛起之前更改實際執行的操作。除非我們把絞刑程序當作UB,也就是說。


查看完整回答
反對 回復 2019-07-10
  • 3 回答
  • 0 關注
  • 563 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號