爲什麼下面喚醒一個編譯時錯誤:詮釋「不能類型隱式轉換'到‘字節’:C#XOR不會編譯沒有投
byte a = 25;
byte b = 60;
byte c = a^b;
這將使意義,如果我使用算術運算符,因爲a + b的結果可能比可以存儲在單個字節中的結果大。
但是將其應用於XOR運算符是毫無意義的。在這裏異或是一個不能溢出字節的按位操作。
使用兩個操作數各地鑄造的工作原理:
byte c = (byte)(a^b);
爲什麼下面喚醒一個編譯時錯誤:詮釋「不能類型隱式轉換'到‘字節’:C#XOR不會編譯沒有投
byte a = 25;
byte b = 60;
byte c = a^b;
這將使意義,如果我使用算術運算符,因爲a + b的結果可能比可以存儲在單個字節中的結果大。
但是將其應用於XOR運算符是毫無意義的。在這裏異或是一個不能溢出字節的按位操作。
使用兩個操作數各地鑄造的工作原理:
byte c = (byte)(a^b);
我不能給你理由,但是我可以從編譯器必須遵循的規則(這可能不是你知道的有趣事情)的立場來看,爲什麼編譯器會有這種行爲。
從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
結果。
+1,很好的答案,Raymond Chen說幾乎相同,微軟認爲類型之間的一致性對易用性很重要。 – Ash 2010-04-28 08:01:27
這是值得推測的,但如果這是動機,那麼它就不會被充分考慮。即使在int操作的情況下,由於整數溢出導致的數據丟失仍然存在。限制字節操作在這方面沒有任何幫助。 – Assimilater 2017-06-21 20:25:59
'ushort'同樣發生在'ushort aa = 1; ushort bb = 1; ushort cc = aa - bb;'無法編譯。 – 2017-10-06 17:18:08
我猜它的,因爲運營商XOR爲布爾和整數定義。
而從整數結果轉換爲字節的結果是一個信息丟失的轉換;因此需要一個明確的演員(從程序員點頭)。
這更多的與CLI規範中有關隱式和顯式轉換的規則有關。一個整數(int = System.Int32 = 4個字節)比一個字節(顯然是1個字節)寬。因此,從int到byte的任何轉換都可能會縮小範圍。因此,編譯器希望你明確這一點。
我認爲海報的驚喜是結果不是另一個字節。 – 2010-04-28 05:11:41
從微軟半仙程序員有一個答案:http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx
也許這更多的是編譯器的設計。它們通過對編譯過程進行概括來簡化編譯器,它不必查看操作數的運算符,因此它將算術運算符與按位運算分類在相同的類別中。因此,受到類型加寬
這似乎是因爲在C#語言規範,它是爲整數定義和長 http://msdn.microsoft.com/en-us/library/aa691307%28v=VS.71%29.aspx
那麼,什麼是真正發生的是,編譯器蒙上字節操作數隱含詮釋,因爲沒有以這種方式丟失數據。但是結果(int)不能在不丟失數據的情況下下載(隱式地)。所以,你需要明確告訴編譯器你知道你在做什麼!
在鏈接的文章中提到的場景中,有什麼有用的是編譯器會根據返回值來fudge運算符重載,或者'〜b'產生的值不是整數類型,而是可以轉換爲根據需要適當大小的一個。這種方法可以幫助像'longVal&=〜intVal;'這樣的情況,'〜'的結果實際上應該是'long'。 – supercat 2012-11-20 23:32:12
至於爲什麼兩個字節必須轉換爲整數才能進行XOR?
如果您想深入研究,CLI Spec(分區I)的12.1.2描述了這樣的事實:在評估堆棧上,只能存在int或long。在評估過程中,所有較短的積分類型都必須擴展。
不幸的是,我找不到直接連接到CLI Spec的合適鏈接 - 我有一個本地副本作爲PDF,但不記得我從哪裏得到它。
FWIW byte a = 25; 字節b = 60; a = a^b; 不起作用。但是 字節a = 25; 字節b = 60; a^= b; 確實有效。
的確很奇怪,按位操作(除了左移以外)不會溢出 – Hao 2010-04-28 05:07:57
字節操作一般可以返回大於255的值,比如當你左移一個字節,當然和/或操作符不生成的結果大於字節,但爲了兼容性,結果將爲int! – 2013-09-07 16:38:43