2009-07-31 2 views
4

У меня есть этот код.OR-ing байтов в C# дает int

byte dup = 0; 
Encoding.ASCII.GetString(new byte[] { (0x80 | dup) }); 

Когда я пытаюсь скомпилировать я получаю:

Не удается неявно преобразовать тип 'INT' к 'байт. Явное преобразование существует (вы лидируете ли?)

Почему это происходит? Не должно | два байта дают байт? Обе следующие работы, гарантирующие, что каждый элемент является байтом.

Encoding.ASCII.GetString(new byte[] { (dup) }); 
Encoding.ASCII.GetString(new byte[] { (0x80) }); 
+0

Этот вопрос отвечает на него более подробно: http://stackoverflow.com/questions/737781/left-bit-shifting-255-as-a-byte. У вас есть строковый литерал, который всегда передается в int. –

ответ

17

Это тот способ, с помощью конструкции в C#, и, по сути, восходит вплоть до C/C++ - последний также способствует операнды int, вы обычно не замечаете, потому что преобразование int -> char неявно, а не в C#. Это относится не только к |, но и ко всем арифметическим и побитовым операндам - ​​например, добавив два byte s, вы получите int. Я процитирую соответствующую часть спецификации здесь:

Binary числовое расширение происходит за операнды предопределенный +, -, *, /,%, &, |, ^, ==,! =,>, <,> =, и < = двоичные операторы. Двоичный числовое продвижение неявно преобразует оба операнда в общий тип, который, в случае нереляционных операторов , также становится результатом типа операции. Binary числовой продвижения состоит из применения следующих правил, в порядке их появляются здесь:

  • Если один из операндов имеют типа десятичного знака, то другой операнд преобразуется к типу десятичного или компиляций -time-ошибка возникает, если другой операнд имеет тип float или double.

  • В противном случае, если один из операндов имеет значение , тип double, другой операнд преобразован в тип double.

  • В противном случае, , если один из операндов имеет тип поплавка, другой операнд преобразуется к типу поплавок.

  • В противном случае, если один из операндов имеет тип ULONG, то другой операнд преобразуется в тип ULong или ошибка времени компиляции происходит, если другой операнд имеет тип SByte, короткий, INT, или длинный.

  • В противном случае, если либо операнд имеет длинный тип, другой операнд преобразуется в длинный.

  • В противном случае, если один из операндов имеет типа UINT, а другой операнд имеет тип SByte, короткий или междунар оба операнды преобразуются к типу долго.

  • В противном случае, если один из операндов имеет тип uint, другой операнд преобразован в тип uint.

  • В противном случае оба операнда преобразуются в тип int.

Я не знаю точное обоснование для этого, но я могу думать об одном. В частности, для арифметических операторов может показаться немного удивительным, что люди внезапно получают (byte)200 + (byte)100, равным 44, даже если это имеет смысл, когда вы тщательно рассматриваете используемые типы. С другой стороны, int обычно считается типом, который «достаточно хорош» для арифметики для большинства типичных чисел, поэтому, продвигая оба аргумента до int, вы получаете своеобразное поведение «просто работает» для большинства распространенных случаев.

Относительно того, почему эта логика была применена и к побитовым операторам - я полагаю, что это в основном для согласованности. Это приводит к одному простому правилу, которое является общим для всех небулевых двоичных типов.

Но все это в основном угадывает. Эрик Липперт, вероятно, должен был спросить о реальных мотивах этого решения для C# по крайней мере (хотя было бы немного скучно, если бы ответ был просто «как это делается на C/C++ и Java, и это достаточно хорошо так как мы не видели причин для его изменения »).

+0

Это действительно интересно. Этот пост заслуживает много голосов :) – Stilgar

+0

сладкий ответ! хорошая деталь! Мог бы использовать фрагмент кода, чтобы продемонстрировать, что исправить его проблему, но все это очень интересно. –

+1

Для полноты можно было бы упомянуть, что операторы '| =' etc выполняются неявно. –

4
byte dup = 0; 
Encoding.ASCII.GetString(new byte[] { (byte)(0x80 | dup) }); 

Результат побитового ИЛИ (|) на два байта всегда является внутр.

+0

Как указывали люди 0x80 - это int literal. независимо от того, проблема под рукой int | byte возвращает int, который не может застревать в байте []. –

6

Литеральный 0x80 имеет тип «int», поэтому вы не обрабатываете байты.

То, что вы можете передать его байту [], работает только потому, что 0x80 (как литерал) находится в диапазоне байтов.

Редактировать: Даже если 0x80 передается в байт, код все равно не будет компилироваться, так как байты oring будут выдавать int. Для его компиляции, в результате или должно быть выброшенными: (byte)(0x80|dup)

+0

true, но все еще не показывает, как это исправить. простое отбрасывание 0x80 в байт по-прежнему приводит к сообщению об ошибке, потому что byte | byte => int. – Lucas

+0

(байт) (0x80 | dup) –

+0

Извините, проголосовали. Не объясняет здесь настоящую проблему: byte | byte = int32. –