2009-07-31 9 views
4

J'ai ce code.OR-octets en C# donne int

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

Quand je tente de compiler je reçois:

Impossible de convertir implicitement le type 'int' à 'octet'. Une conversion explicite existe (manque-t-il une distribution?)

Pourquoi cela se produit-il? Ne devrait pas | deux octets donnent un octet? Les deux travaux suivants, assurant que chaque élément est un octet.

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

Cette question répond à la question plus détaillée: http://stackoverflow.com/questions/737781/left-bit-shifting-255-as-a-byte. Vous avez un littéral de chaîne qui est toujours converti en int. –

Répondre

17

Il est de cette façon par la conception en C#, et, en fait, remonte tout le chemin à C/C++ - celui-ci favorise également opérandes à int, vous ne remarquez généralement pas car la conversion int -> char est implicite, alors qu'elle n'est pas en C#. Cela ne s'applique pas seulement à |, mais à tous les opérandes arithmétiques et bitwise - par ex. ajouter deux byte vous donnera aussi un int. Je vais citer la partie pertinente de la spécification ici:

promotion numérique binaire se produit pour opérandes du prédéfini +, -, * , /,%, &, |, ^, ==,! =,>, <,> =, et < = opérateurs binaires. Binary promotion numérique convertit implicitement les deux opérandes à un type commun qui, dans le cas des opérateurs non relationnels , devient également le résultat type de l'opération. promotion numérique binaire consiste à appliquer les règles suivantes, dans l'ordre apparaissent ici:

  • Si l'un des opérandes est de décimal de type, l'autre opérande est convertie en type décimal, ou une compilation -l'erreur de l'heure se produit si l'autre opérande est de type float ou double.

  • Sinon, si l'un des opérandes est de type double, l'autre opérande est converti en type double.

  • Sinon, si l'un des opérandes est de type float, l'autre opérande est convertie en type flotteur.

  • Sinon, si l'opérande est de type ulong, l'autre opérande est converties au type ulong, ou une erreur de compilation se produit si l'autre opérande est de type sbyte, short, int, ou longue.

  • Sinon, si l'opérande est de type long, l'autre opérande est converti en type long.

  • Dans le cas contraire, si l'un des opérandes est de de type uint et l'autre opérande est de de type sbyte, à court ou int, les deux opérandes sont convertis en type long.

  • Sinon, si l'un des opérandes est de type 0int, l'autre opérande est converti en type uint.

  • Sinon, les deux opérandes sont convertis en type int.

Je ne sais pas la raison exacte pour cela, mais je ne peux penser à un. Pour les opérateurs arithmétiques en particulier, il peut être un peu surprenant pour les gens d'obtenir (byte)200 + (byte)100 soudainement égal à 44, même si cela a du sens quand on considère attentivement les types impliqués. D'autre part, int est généralement considéré comme un type qui est "assez bon" pour l'arithmétique sur la plupart des nombres typiques, donc en promouvant les deux arguments à int, vous obtenez un genre de "fonctionne juste" comportement pour les cas les plus courants.

En ce qui concerne la raison pour laquelle cette logique a également été appliquée aux opérateurs bit à bit - j'imagine que c'est principalement le cas pour la cohérence. Il en résulte une seule règle simple qui est commune pour tous les types binaires non booléens.

Mais tout cela est principalement deviné. Eric Lippert serait probablement le seul à s'interroger sur les véritables motivations derrière cette décision pour C# au moins (bien que ce serait un peu ennuyeux si la réponse est simplement "c'est comme ça en C/C++ et Java, et c'est assez bon la règle telle qu'elle est, donc nous n'avons vu aucune raison de le changer ").

+0

C'est vraiment intéressant. Ce post mérite beaucoup de votes :) – Stilgar

+0

douce réponse! bon détail! Pourrait avoir utilisé un extrait de code pour démontrer ce qui permettrait de résoudre son problème, mais dans l'ensemble très intéressant. –

+1

Pour être complet, il convient de mentionner que les opérateurs '| =' etc font implicitement un cast. –

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

Le résultat d'une opération de bits ou (|) sur deux octets est toujours un entier.

+0

Comme les gens ont souligné 0x80 est un littéral int. Peu importe, le problème est int | byte renvoie un int, qui ne peut pas être bloqué dans un octet []. –

6

Le littéral 0x80 a le type "int", donc vous n'émettez pas d'octets.

Que vous pouvez le passer à l'octet [] ne fonctionne que parce que 0x80 (en tant que littéral), il est dans la plage de l'octet.

Édition: Même si 0x80 est converti en octet, le code ne compilera toujours pas, puisque les octets continueront de donner int. Pour avoir la compilation, le résultat du ou doit être jeté: (byte)(0x80|dup)

+0

vrai, mais ne montre toujours pas comment résoudre ce problème. la simple conversion de 0x80 en octets entraîne toujours un message d'erreur, car byte | byte => int. – Lucas

+0

(octet) (0x80 | dup) –

+0

Désolé, voté bas. N'explique pas le vrai problème en jeu ici: byte | octet = int32. –