在 cppreference.com 的“隱式轉換”部分的“左值轉換”小節中,注意到
[i]如果左值指定了一個自動存盤持續時間的物件,其地址從未被占用,并且如果該物件未初始化(未使用初始化程式宣告并且在使用之前未對其進行分配),則行為未定義。[強調我的]
由此,我不明白物件在某個時間點的“獲取地址的行為”可能會以某種方式影響未定義的行為是否在以后“使用”該物件時發生。如果我是對的,那么至少看起來不尋常。
我對嗎?如果是這樣,那怎么可能?如果沒有,我錯過了什么?
uj5u.com熱心網友回復:
cppreference.com 是從 C 標準中的規則推匯出來的。C 2018 6.3.2 2 說:
如果左值指定了一個可以使用存盤類宣告的具有自動存盤持續時間的物件
register(從未使用過它的地址),并且該物件未初始化(未使用初始化程式宣告并且在使用之前未對其進行分配) ,行為未定義。
因此,獲取地址之所以重要,根本上是因為“C 標準是這樣說的”,而不是因為獲取地址在計算模型中“做某事”。
將此規則添加到 C 標準的原因是為了支持 Hewlett-Packard (HP) 對其 Itanium 處理器所需的某些行為。在該處理器中,某些暫存器中的每一個都有一個關聯的位,指示該暫存器“未初始化”。因此,HP 能夠讓程式在某些未初始化物件的情況下進行檢測和捕獲。(此檢測不會擴展到記憶體;該位僅與處理器暫存器相關聯。)
通過說如果使用未初始化的物件,行為是未定義的,C 標準允許發生陷阱,但也允許可能不發生陷阱。因此它允許 HP 的捕獲行為,當 HP 的軟體沒有檢測到問題并因此沒有捕獲時,它允許它,它允許其他供應商忽略這一點并提供暫存器中發生的任何值,以及其他行為可能來自編譯器的優化。
至于基于自動存盤持續時間而不是獲取地址來預測未定義的行為,我懷疑這有點混亂。它提供了一個適用于相關各方的標準:HP 能夠設計他們的編譯器來使用他們的暫存器的“未初始化”功能,但該規則并沒有將大量物件使用劃分為未定義的行為。例如,有人可能想要撰寫一個演算法來處理大量陣列的大部分,忽略定義區域的“沿邊緣”的一些值可能未初始化。這樣的想法是,在某些情況下,執行一個操作塊會更有效,然后在最后切掉你不關心的那些。因此,對于這些情況,程式員希望代碼使用“不確定的值”——代碼將執行,將到達操作的末尾,并且在關心的結果中將具有有效值,并且不會有任何由他們不關心的值引起的陷阱或其他未定義的行為。因此,將未初始化物件的未定義行為限制為未獲取地址的自動物件可能提供了一個適用于所有相關方的邊界。
uj5u.com熱心網友回復:
如果一個物件的地址從未被占用,它可能會被優化掉。在這種情況下,嘗試讀取未初始化的變數不需要在多次讀取時產生相同的值。
通過獲取物件的地址,可以保證為它預留存盤空間,然后可以從中讀取。假設它不是陷阱表示,那么讀取的值將至少是一致的(盡管不一定是可預測的)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/520843.html
標籤:C目的未定义行为左值
上一篇:如何在陣列中的陣列中添加物件
