2012-03-01 36 views
4
public void Foo(double d){ 
    // when called below, d == 2^32-1 
    ... 
} 
public void Bar(){ 
    uint ui = 1; 
    Foo(0 - ui); 
} 

我希望在這裏將0和ui都提升爲有符號的longs。C#0(減號)uint =無符號結果?

真,用0字面是在編譯的時候,強制轉換爲UINT安全可知,

但我想這一切似乎只是錯誤的。至少應該發出警告。

謝謝!

語言規範是否涵蓋了這樣的半含糊的情況?

+5

這個問題等待Jon Skeet :) – 2012-03-01 23:06:38

+2

不長:-) – 2012-03-01 23:11:46

回答

0

這就是int,它正被轉換爲uint以執行從0減去(這被編譯器隱含地解釋爲uint)。請注意,intuint是一個隱式轉換,因此沒有警告。你的代碼沒有問題......除了uint不是CLS編譯器。你可以閱讀爲什麼here。有關CLS編譯代碼的更多信息MSDN

+1

'int'到'uint'通常不是一個隱式轉換 - 這是一個*隱式常量表達式轉換*。參見規範的6.1.9節。如果我們開始使用'int' *變量*,那麼就會提升爲'long'。 (兩個'int'和'uint'可以隱式轉換爲'long'。) – 2012-03-01 23:20:47

+0

@JonSkeet感謝澄清:) – SiliconMind 2012-03-02 10:00:48

+0

接受這個答案,因爲我的困惑的根本原因很簡單,零隱式轉換爲uint。基於0是int的假設,我期望推廣長... – mike 2012-03-06 22:18:43

7

爲什麼要提升到long?該規範(部分7.8.5)列出了四個操作爲整數減法:

  • int operator-(int x, int y);
  • uint operator-(uint x, uint y);
  • long operator-(long x, long y);
  • ulong operator-(ulong x, ulong y);

鑑於恆定值0隱式轉換爲uint,但uintui而不是可以隱式轉換爲int,第二個運算符根據7.3.4節中描述的二元運算符重載分辨率步驟進行選擇。

(難道你不知道有隱含的常量表達式轉換從0uint,因此這是混亂的一部分嗎?請參見C#4規格的細節部分6.1.9)

下一節7.3.4(然後參考7.3.5和7.5.3)稍微有些曲折,但我認爲它是明確的,並且一點也不含糊。

如果這是溢出困擾你,預計這個也會失敗?

int x = 10; 
int y = int.MaxValue - 5; 
int z = x + y; 

如果沒有,什麼是真正這裏的區別?

+0

我認爲他的問題更多的是(潛在)不明確的結果值。即如果我從0減去一個正數,我不應該得到一個積極的結果。與你的int例子類似,向正數加10不應該導致負數。如果你在處理數字上的這些類型的邊界問題,我會遇到的一個問題是不是最好使用'checked'來確保你的結果不含糊不清(至少對你來說不明確) – NominSim 2012-03-01 23:29:58

+0

@NominSim:有這裏沒有歧義。它的行爲*正如說明書規定的那樣。如果OP想要使用checked context,那麼他們絕對可以,但是這裏不需要警告,並且它的行爲都是正確的。我相信OP的* actual *問題在於它使用'uint'算術執行,而他期望它使用'long'算術:「我希望這裏將0和ui提升爲有符號長整數。」 – 2012-03-02 00:06:23

+0

我知道它的行爲完全符合規範要求,模糊不在規範中,而是在行爲中,如果我從負數中減去保證的正數,我應該得到否定結果。這就是爲什麼我認爲OP應該使用被檢查的上下文,如果他們正在處理可能導致出於特定數據結構的邊界的數字。 – NominSim 2012-03-02 13:41:19

0

在已檢查的上下文中,如果差異超出結果類型的範圍,則會引發System.OverflowException。在未檢查的上下文中,不報告溢出,並且丟棄結果類型範圍之外的任何重要的高位。

http://msdn.microsoft.com/en-us/library/aa691376(v=vs.71).aspx

技術上,執行以下操作:

double d = checked(0-ui); 

將導致System.OverflowException投擲這是你期望也許什麼,而是根據規範,因爲這是不檢查溢出未報告。