Байты OR в C# дают int [дубликат]
-
06-07-2019 - |
Вопрос
На этот вопрос уже есть ответ здесь:
- Сдвиг левого бита 255 (как байт) 7 ответов
У меня есть этот код.
byte dup = 0;
Encoding.ASCII.GetString(new byte[] { (0x80 | dup) });
Когда я пытаюсь скомпилировать, я получаю:
Не может косвенно преобразовать тип «int» в байт '.Существует явное преобразование (вам не хватает актерского состава?)
Почему это происходит?Не должен | Два байта дают байт?Оба следующих варианта работают, гарантируя, что каждый элемент является байтом.
Encoding.ASCII.GetString(new byte[] { (dup) });
Encoding.ASCII.GetString(new byte[] { (0x80) });
Решение
Так задумано в C#, и фактически оно восходит к C/C++ — последний также переводит операнды в int
, ты обычно этого не замечаешь, потому что int -> char
преобразование там неявное, хотя в C# его нет.Это касается не только |
либо, но для всех арифметических и побитовых операндов - например.добавление двух byte
s даст вам int
также.Я процитирую соответствующую часть спецификации здесь:
Бинарная числовая промоушена происходит для операндов предопределенного +, -, *, /, %, &, |, ^, ==,! =,>, <,> = И <= бинарных операторов.Бинарная числовая пропаганда неявно преобразует оба операнда в общий тип, который, в случае нереляционных операторов, также становится типом результата операции.Бинарная числовая пропаганда состоит из применения следующих правил, в том порядке, в котором они появляются здесь:
Если любой операнд имеет десятичное значение типа, другой операнд преобразуется в децимал типа, или возникает ошибка времени компиляции, если другой операнд имеет тип плавания или вдвое.
В противном случае, если любой операнд имеет двойной, другой операнд преобразуется в тип двойного.
В противном случае, если любой операнд имеет тип float, другой операнд преобразуется в Type Float.
В противном случае, если любой операнд имеет тип Ulong, другой операнд преобразуется в тип Ulong, или возникает ошибка времени компиляции, если другой операнд имеет тип Sbyte, Short, Int или Long.
В противном случае, если любой операнд имеет длинный тип, другой операнд преобразуется в тип длинного.
В противном случае, если один операнд имеет тип Uint, а другой операнд имеет тип Sbyte, Short или Int, оба операнда преобразуются в Long.
В противном случае, если любой операнд имеет тип Uint, другой операнд преобразуется в тип Uint.
В противном случае оба операнда преобразуются в тип Int.
Я не знаю точного обоснования этого, но могу подумать об одном.Особенно для арифметических операторов может быть немного удивительно получить (byte)200 + (byte)100
вдруг станет равным 44
, даже если это имеет некоторый смысл, если внимательно рассмотреть задействованные типы.С другой стороны, int
обычно считается типом, который «достаточно хорош» для арифметических вычислений с большинством типичных чисел, поэтому, повышая оба аргумента до int
, в большинстве распространенных случаев вы получаете своего рода поведение «просто работает».
Что касается того, почему эта логика была также применена к побитовым операторам - я думаю, это в основном для обеспечения согласованности.В результате получается одно простое правило, общее для все нелогические двоичные типы.
Но это все в основном догадки.Эрик Липперт, вероятно, был бы тем, кто спросил бы о реальных мотивах этого решения, по крайней мере, для C# (хотя было бы немного скучно, если бы ответ был просто «так это делается в C/C++ и Java, и это достаточно хорошо». правило в его нынешнем виде, поэтому мы не видели причин его менять»).
Другие советы
Литерал 0x80 имеет тип «int», поэтому вы не обрабатываете байты.
То, что вы можете передать его в byte[], работает только потому, что 0x80 (как литерал) находится в диапазоне байтов.
Редактировать:Даже если 0x80 привести к байту, код все равно не скомпилируется, поскольку при операции oring байты все равно будут выдаваться int.Чтобы он скомпилировался, необходимо привести результат or: (byte)(0x80|dup)
byte dup = 0;
Encoding.ASCII.GetString(new byte[] { (byte)(0x80 | dup) });
Результатом побитового ИЛИ (|) для двух байтов всегда является целое число.