2010-04-28 22 views
26

爲什麼下面喚醒一個編譯時錯誤:詮釋「不能類型隱式轉換'到‘字節’:C#XOR不會編譯沒有投

 byte a = 25; 
     byte b = 60; 

     byte c = a^b; 

這將使意義,如果我使用算術運算符,因爲a + b的結果可能比可以存儲在單個字節中的結果大。

但是將其應用於XOR運算符是毫無意義的。在這裏異或是一個不能溢出字節的按位操作。

使用兩個操作數各地鑄造的工作原理:

byte c = (byte)(a^b); 
+0

的確很奇怪,按位操作(除了左移以外)不會溢出 – Hao 2010-04-28 05:07:57

+0

字節操作一般可以返回大於255的值,比如當你左移一個字節,當然和/或操作符不生成的結果大於字節,但爲了兼容性,結果將爲int! – 2013-09-07 16:38:43

回答

22

我不能給你理由,但是我可以從編譯器必須遵循的規則(這可能不是你知道的有趣事情)的立場來看,爲什麼編譯器會有這種行爲。

從C#規範的舊副本(也許我應該下載更新的版本),加上強調:

14.2.6.2 Binary numeric promotions This clause is informative.

Binary numeric promotion occurs for the operands of the predefined + , ? , * , / , % , & , | , ^ , == , != , > , < , >= , and <= binary operators. Binary numeric promotion implicitly converts both operands to a common type which, in case of the non-relational operators, also becomes the result type of the operation. Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • If either operand is of type decimal, the other operand is converted to type decimal, or a compile-time error occurs if the other operand is of type float or double.
  • Otherwise, if either operand is of type double, the other operand is converted to type double.
  • Otherwise, if either operand is of type float, the other operand is converted to type float.
  • Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a compile-time error occurs if the other operand is of type sbyte, short, int, or long.
  • Otherwise, if either operand is of type long, the other operand is converted to type long.
  • Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
  • Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • Otherwise, both operands are converted to type int.

所以,基本上操作數比int將被轉換爲int爲這些運營商小(對於非關係操作,結果將是int)。

我說我不能給你一個理由;然而,我會猜測其中一個 - 我認爲C#的設計人員想要確保那些可能會丟失信息的操作如果縮小,需要程序員以演員形式明確地進行縮小操作。例如:

byte a = 200; 
byte b = 100; 

byte c = a + b; // value would be truncated 

在執行兩張字節數之間的XOR運算時,這種截斷的情況不會發生,我認爲語言的設計者可能不希望有一個更復雜的規則,其中一些操作將需要明確的轉換,而其他操作不需要。


只是一個小注:以上報價「信息」不「規範」,但它涵蓋了一個簡單的所有的情況下閱讀的形式。嚴格地說(在規範意義上)的原因^運營商的行爲這種方式是因爲byte操作數處理該運營商最近的過載時(從14.10.1「整數邏輯運算符」):

int operator ^(int x, int y); 

因此,正如資料性文字所解釋的那樣,操作數被提升爲int,並且產生了一個int結果。

+0

+1,很好的答案,Raymond Chen說幾乎相同,微軟認爲類型之間的一致性對易用性很重要。 – Ash 2010-04-28 08:01:27

+0

這是值得推測的,但如果這是動機,那麼它就不會被充分考慮。即使在int操作的情況下,由於整數溢出導致的數據丟失仍然存在。限制字節操作在這方面沒有任何幫助。 – Assimilater 2017-06-21 20:25:59

+0

'ushort'同樣發生在'ushort aa = 1; ushort bb = 1; ushort cc = aa - bb;'無法編譯。 – 2017-10-06 17:18:08

1

我猜它的,因爲運營商XOR爲布爾和整數定義。

而從整數結果轉換爲字節的結果是一個信息丟失的轉換;因此需要一個明確的演員(從程序員點頭)。

0

這更多的與CLI規範中有關隱式和顯式轉換的規則有關。一個整數(int = System.Int32 = 4個字節)比一個字節(顯然是1個字節)寬。因此,從int到byte的任何轉換都可能會縮小範圍。因此,編譯器希望你明確這一點。

+1

我認爲海報的驚喜是結果不是另一個字節。 – 2010-04-28 05:11:41

2

從微軟半仙程序員有一個答案:http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx

也許這更多的是編譯器的設計。它們通過對編譯過程進行概括來簡化編譯器,它不必查看操作數的運算符,因此它將算術運算符與按位運算分類在相同的類別中。因此,受到類型加寬

+1

我剛剛讀過。他實際上是在談論算術運算符而不是按位進行。他在評論中同意他的觀點對於按位運算符無效。 – Ash 2010-04-28 05:16:08

+0

@Ash:很高興問他。也許安德斯應該修改編譯器並使其更加智能化,而且C沒有這種行爲 – 2010-04-28 05:18:38

+0

這是因爲C通常不需要在不同大小的整數之間進行顯式轉換。 – dan04 2010-04-28 05:44:22

0

我以爲我記得一個關於此問題的流行問題。

byte + byte = int... why?

+0

這不是一回事。添加兩個字節可能會溢出。異或兩個字節不能。 – dan04 2010-04-28 05:39:12

0

這似乎是因爲在C#語言規範,它是爲整數定義和長 http://msdn.microsoft.com/en-us/library/aa691307%28v=VS.71%29.aspx

那麼,什麼是真正發生的是,編譯器蒙上字節操作數隱含詮釋,因爲沒有以這種方式丟失數據。但是結果(int)不能在不丟失數據的情況下下載(隱式地)。所以,你需要明確告訴編譯器你知道你在做什麼!

+0

在鏈接的文章中提到的場景中,有什麼有用的是編譯器會根據返回值來fudge運算符重載,或者'〜b'產生的值不是整數類型,而是可以轉換爲根據需要適當大小的一個。這種方法可以幫助像'longVal&=〜intVal;'這樣的情況,'〜'的結果實際上應該是'long'。 – supercat 2012-11-20 23:32:12

0

至於爲什麼兩個字節必須轉換爲整數才能進行XOR?

如果您想深入研究,CLI Spec(分區I)的12.1.2描述了這樣的事實:在評估堆棧上,只能存在int或long。在評估過程中,所有較短的積分類型都必須擴展。

不幸的是,我找不到直接連接到CLI Spec的合適鏈接 - 我有一個本地副本作爲PDF,但不記得我從哪裏得到它。

-1

FWIW byte a = 25; 字節b = 60; a = a^b; 不起作用。但是 字節a = 25; 字節b = 60; a^= b; 確實有效。