Подтвердить что ты не робот

С# XOR по двум байтовым переменным не будет компилироваться без литья

Почему возникает следующая ошибка времени компиляции: "Невозможно неявно преобразовать тип" int "в" byte ":

        byte a = 25;
        byte b = 60;

        byte c = a ^ b;

Это имело бы смысл, если бы я использовал оператор арифметики, потому что результат a + b мог быть больше, чем может быть сохранен в одном байте.

Однако применение этого к оператору XOR бессмысленно. XOR здесь это побитовая операция, которая никогда не может переполнять байты.

используя эффект броска вокруг обоих операндов:

byte c = (byte)(a ^ b);
4b9b3361

Ответ 1

Я не могу дать вам обоснование, но я могу понять, почему компилятор имеет такое поведение с точки зрения правил, которым должен следовать компилятор (что может быть не совсем то, что вам интересно знать).

Из старой копии спецификации С# (возможно, я должен загрузить более новую версию), добавлено выделение:

14.2.6.2 Двоичные числовые акции Этот раздел является информативным.

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

  • Если один из операндов имеет тип decimal, другой операнд преобразуется в десятичный тип или ошибка компиляции возникает, если другая операнд имеет тип float или double.
  • В противном случае, если любой из операндов имеет тип double, другой операнд преобразованный в тип double.
  • В противном случае, если любой операнд имеет тип float, другой операнд преобразуется в тип float.
  • В противном случае, если один из операндов имеет тип ulong, другой операнд преобразуется в тип ulong или ошибка компиляции возникает, если другая операнд имеет тип sbyte, short, int, или долго.
  • В противном случае, если любой из операндов имеет тип long, другой операнд преобразованный в тип long.
  • В противном случае, если любой операнд имеет тип uint, а другой операнд тип sbyte, short или int, оба операнды преобразуются в тип long.
  • В противном случае, если любой операнд имеет тип uint, другой операнд преобразован в тип uint.
  • В противном случае оба операнда преобразуются в тип int.

Таким образом, в основном операнды, меньшие, чем int, будут преобразованы в int для этих операторов (и результат будет int для нереляционных ops).

Я сказал, что не могу дать вам обоснования; однако я сделаю предположение о том, что разработчики С# хотели удостовериться, что операции, которые могут потерять информацию, если сузить, должны были бы выполнять эту операцию сужения, явно выраженную программистом в форме приведения. Например:

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.

Ответ 2

У программиста полубога из Microsoft есть ответ: http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx

И, возможно, это больше о дизайне компилятора. Они упрощают компилятор, обобщая процесс компиляции, он не должен рассматривать оператор операндов, поэтому он объединяет побитовые операции в той же категории, что и арифметические операторы. Тем самым подвергается расширению типа

Ссылка мертвая, архив тут:

https://web.archive.org/web/20140118171646/http://blogs.msdn.com/b/oldnewthing/archive/2004/03/10/87247.aspx

Ответ 3

Я предполагаю, потому что оператор XOR определен для булевых и целых чисел.

И приведение результата от целочисленного результата в байт является потеряющим информацию преобразованием; поэтому требуется явное приведение (кивок от программиста).

Ответ 4

Это больше связано с правилами, связанными с неявным и явным литьем в спецификации CLI. Целое число (int = System.Int32 = 4 байта) шире байта (1 байт, очевидно!). Поэтому любой отбор из int в байт потенциально сужается. Поэтому компилятор хочет, чтобы вы сделали это явным.

Ответ 6

Похоже, что в спецификациях языка С# он определен для целых и длинных http://msdn.microsoft.com/en-us/library/aa691307%28v=VS.71%29.aspx

Итак, на самом деле происходит то, что компилятор передает байтовые операнды в int неявно, потому что нет такой потери данных. Но результат (который является int) нельзя отбрасывать без потери данных (неявно). Итак, вам нужно прямо сказать компилятору, что вы знаете, что делаете!

Ответ 7

Как объяснить, почему два байта должны быть преобразованы в int для выполнения XOR?

Если вы хотите вникнуть в него, 12.1.2 спецификации CLI (раздел I) описывает тот факт, что в стеке оценки может существовать только int или long. Все более короткие интегральные типы должны быть расширены во время оценки.

К сожалению, я не могу найти подходящую ссылку непосредственно в CLI Spec - у меня есть локальная копия в формате PDF, но не могу вспомнить, откуда я ее получил.

Ответ 8

FWIW   байт a = 25;   байт b = 60;   a = a ^ b; не работает. Однако   байт a = 25;   байт b = 60;   a ^ = b; действительно работает.