2010-04-28 8 views
26

¿Por qué la siguiente elevar un error de tiempo de compilación: 'No se puede convertir implícitamente el tipo 'int' a 'bytes':C# XOR de dos variables byte no se compilará sin una conversión

 byte a = 25; 
     byte b = 60; 

     byte c = a^b; 

Esto tendría sentido si Estaba usando un operador de aritmética porque el resultado de a + b podría ser mayor de lo que se puede almacenar en un solo byte.

Sin embargo, aplicar esto al operador XOR no tiene sentido. XOR aquí es una operación bit a bit que nunca puede desbordar un byte.

utilizando un molde alrededor de ambos operandos funciona:

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

de hecho es extraño, las operaciones a nivel de bits (bueno, excepto para cambiar a la izquierda) no se desbordan – Hao

+0

operaciones de bytes en general pueden devolver valores mayores que 255, como cuando dejó un byte, por supuesto y/o los operadores no lo hacen generar resultados más grandes que byte, pero por el bien de la compatibilidad, el resultado será int! –

Respuesta

22

No puedo darte el razonamiento, pero puedo decir por qué el compilador tiene ese comportamiento desde el punto de vista de las reglas que el compilador debe seguir (lo que realmente no es lo que te interesa saber).

De una vieja copia de la especificación C# (probablemente debería descargar una versión más reciente), énfasis añadido:

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.

Así que, básicamente operandos más pequeño que un int se convertirá en int para estos operadores (y el resultado será un int para las operaciones no relacionales).

Dije que no podía darle un razonamiento; sin embargo, adivinaré uno: creo que los diseñadores de C# querían asegurarse de que las operaciones que podrían perder información si se redujeran necesitarían tener esa operación de reducción explícita por el programador en forma de un reparto. Por ejemplo:

byte a = 200; 
byte b = 100; 

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

Si bien este tipo de truncamiento no ocurriría cuando se realiza una operación XOR entre dos operandos de byte, creo que los diseñadores del lenguaje probablemente no quiere tener un conjunto más complejo de reglas, donde algunos las operaciones necesitarían moldes explícitos y otras no.


Sólo una pequeña nota: la cita anterior es 'informativo' no 'normativo', pero cubre todos los casos en una forma fácil de leer. En sentido estricto (en un sentido normativo), la razón por la que el operador ^ se comporta de esta manera es porque la sobrecarga más cercano para que el operador cuando se trata de byte operandos está (de 14.10.1 "operadores lógicos entero"):

int operator ^(int x, int y); 

Por lo tanto, como explica el texto informativo, los operandos se promocionan a int y se produce un resultado int.

+0

+1, Buena respuesta, Raymond Chen dijo más o menos lo mismo, Microsoft cree que la consistencia entre los tipos es importante para facilitar el uso. – Ash

+0

Es una suposición digna, pero si ese fuera el motivo, entonces no se hubiera pensado lo suficiente. Incluso en el caso de las operaciones 'int', la pérdida de datos debido al desbordamiento de enteros todavía está allí. Restringir las operaciones byte-wise no ayuda NADA en este sentido. – Assimilater

+0

Lo mismo ocurre con 'ushort' con' ushort aa = 1; ushort bb = 1; ushort cc = aa - bb; 'no se puede compilar. –

1

supongo que es debido a que el operador XOR se define para booleanos y enteros.

Y una conversión del resultado del resultado entero a un byte es una conversión que pierde información; por lo tanto, necesita un molde explícito (asentimiento del programador).

0

Esto tiene más que ver con las reglas que rodean la fundición implícita y explícita en la especificación CLI. Un entero (int = System.Int32 = 4 bytes) es más ancho que un byte (1 byte, ¡obviamente!). Por lo tanto, cualquier conversión de int a byte es potencialmente un lanzamiento estrecho. Por lo tanto, el compilador quiere que hagas esto explícito.

+1

Creo que la sorpresa aquí para el póster es que el resultado no es otro byte. –

2

El programador semi-dios de Microsoft tiene una respuesta: http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx

Y tal vez es más sobre el diseño del compilador. Hacen que el compilador sea más simple al generalizar el proceso de compilación, no tiene que mirar al operador de los operandos, por lo que agrupa las operaciones bit a bit en la misma categoría que los operadores aritméticos. De este modo, sujeto a la ampliación de tipo

+1

Acabo de leer eso. En realidad estaba hablando de operadores aritméticos no bit a bit. Él está de acuerdo en los comentarios que su punto no es válido para operadores bit a bit. – Ash

+0

@Ash: agradable por preguntarle. tal vez Anders debería modificar el compilador y hacerlo más inteligente, y afaict C no tiene ese comportamiento –

+0

Esto se debe a que C, en general, no requiere conversión explícita entre diferentes tamaños de enteros. – dan04

0

pensé que recordaba una pregunta popular sobre esto.

byte + byte = int... why?

+0

No es exactamente lo mismo. Agregar dos bytes puede desbordarse. XORing dos bytes no puede. – dan04

0

parece ser debido a que en las especificaciones de lenguaje C#, que se define por entero y largo http://msdn.microsoft.com/en-us/library/aa691307%28v=VS.71%29.aspx

Por lo tanto, lo que realmente sucede es que el compilador arroja operandos de byte a int implícitamente porque no hay pérdida de datos de esa manera. Pero el resultado (que es int) no se puede bajar sin pérdida de datos (implícitamente). Entonces, ¡tienes que decirle al compilador explícitamente que sabes lo que estás haciendo!

+0

Lo que sería útil en el escenario mencionado por el artículo vinculado sería que el compilador borre la sobrecarga del operador en función del valor de retorno, o bien tenga '~ b' para obtener un valor que no sea un tipo entero, pero que se pueda convertir a tamaño apropiado según sea necesario. Tal enfoque podría ayudar con casos como 'longVal & = ~ intVal;', donde el resultado de '~ 'realmente debería ser' long'. – supercat

0

¿En cuanto a por qué los dos bytes deben convertirse a ints para hacer el XOR?

Si desea profundizar en ello, 12.1.2 de la CLI Spec (Partition I) describe el hecho de que, en la pila de evaluación, solo pueden existir int o long. Todos los tipos integrales más cortos deben expandirse durante la evaluación.

Desafortunadamente, no encuentro un enlace adecuado directamente a la especificación de la CLI. Tengo una copia local como PDF, pero no recuerdo dónde la obtuve.

-1

FWIW byte a = 25; byte b = 60; a = a^b; no funciona. Sin embargo, byte a = 25; byte b = 60; a^= b; funciona.

Cuestiones relacionadas