2010-04-28 5 views
26

Pourquoi le suivant soulève une erreur de compilation: « Impossible de convertir implicitement le type « int » à « octet »:C# XOR sur deux variables d'octets ne compilera pas sans un casting

 byte a = 25; 
     byte b = 60; 

     byte c = a^b; 

Cela aurait du sens si J'utilisais un opérateur arithmentic parce que le résultat de a + b pouvait être plus grand que ce qui peut être stocké dans un seul octet. Cependant, l'appliquer à l'opérateur XOR est inutile. XOR ici c'est une opération au niveau du bit qui ne peut jamais déborder d'un octet.

en utilisant un casting autour des deux opérandes fonctionne:

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

en effet c'est bizarre, les opérations binaires (bien sauf pour passer à gauche) ne débordent pas – Hao

+0

octets opérations en général peuvent retourner des valeurs supérieures à 255, comme lorsque vous avez quitté déplacer un octet, bien sûr et/ou les opérateurs ne générer des résultats plus gros que des octets mais pour des raisons de compatibilité, le résultat sera int! –

Répondre

22

Je ne peux pas vous donner la raison, mais je peux dire pourquoi le compilateur a ce comportement du point de vue des règles que le compilateur doit suivre (ce qui n'est peut-être pas ce que vous voulez savoir).

D'une ancienne copie de la spécification C# (je devrais probablement télécharger une version plus récente), l'accent a ajouté:

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.

Ainsi, opérandes essentiellement plus petit qu'un int sera converti en int pour ces opérateurs (et le résultat sera un int pour les opérations non relationnelles).J'ai dit que je ne pouvais pas vous donner de raison d'être; Cependant, je vais faire une supposition à un - je pense que les concepteurs de C# voulait s'assurer que les opérations qui pourraient perdre des informations si rétréci aurait besoin d'avoir cette opération de rétrécissement rendue explicite par le programmeur sous la forme d'une distribution. Par exemple:

byte a = 200; 
byte b = 100; 

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

Bien que ce genre de troncature ne se produira pas lors de l'exécution d'une opération XOR entre deux opérandes octet, je pense que les concepteurs de langage ne voulait probablement pas avoir un ensemble de règles plus complexes où certains les opérations nécessiteraient des conversions explicites et d'autres non.


Juste une petite note: la citation ci-dessus est « d'information » et non « normatif », mais il couvre tous les cas dans une forme facile à lire. Au sens strict (dans un sens normatif), la raison pour laquelle l'opérateur ^ se comporte de cette façon est le plus proche parce que la surcharge pour cet opérateur face à des byte opérandes est (à partir 14.10.1 « opérateurs logiques Integer »):

int operator ^(int x, int y); 

Par conséquent, comme l'explique le texte informatif, les opérandes sont promus à int et un résultat int est produit.

+0

+1, Belle réponse, Raymond Chen a dit à peu près la même chose, Microsoft croit que la cohérence entre les types est importante pour la facilité d'utilisation. – Ash

+0

C'est une bonne idée, mais si c'était le motif, il n'aurait pas été suffisamment réfléchi. Même dans le cas des opérations 'int', la perte de données due au débordement d'entier est toujours là. Restreindre les opérations par octet ne contribue à rien à cet égard. – Assimilater

+0

Même chose pour 'ushort' avec' ushort aa = 1; ushort bb = 1; ushort cc = aa - bb; 'échoue à compiler. –

1

Je suppose que parce que l'opérateur XOR est défini pour booléens et entiers.

Et une conversion du résultat du résultat entier en un octet est une conversion perdant des informations; a donc besoin d'une distribution explicite (acquiescement du programmeur).

0

Ceci a plus à voir avec les règles entourant le moulage implicite et explicite dans la spécification CLI. Un entier (int = System.Int32 = 4 octets) est plus large qu'un octet (1 octet, évidemment!). Par conséquent, toute conversion de int en octet est potentiellement un casting rétréci. Par conséquent, le compilateur veut que vous rendiez cela explicite.

+1

Je pense que la surprise ici pour l'affiche est que le résultat n'est pas un autre octet. –

2

Le programmeur de Microsoft a deva une réponse: http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx

Et peut-être il est plus sur la conception du compilateur. Ils rendent le compilateur plus simple en généralisant le processus de compilation, il n'a pas à regarder l'opérateur des opérandes, donc il a regroupé les opérations au niveau du bit dans la même catégorie que les opérateurs arithmétiques. Par conséquent, soumis à l'élargissement de type

+1

Je viens de lire ça. Il parlait en fait d'opérateurs arithmétiques non bitwise. Il accepte dans les commentaires que son point n'est pas valide pour les opérateurs au niveau du bit. – Ash

+0

@Ash: sympa de lui demander. peut-être Anders devrait modifier le compilateur et le rendre plus intelligent, et afaict C n'a pas ce comportement –

+0

C'est parce que C, en général, ne nécessite pas de conversion explicite entre différentes tailles d'entiers. – dan04

0

Je pensais que je me souvenais d'une question populaire à ce sujet.

byte + byte = int... why?

+0

Ce n'est pas tout à fait la même chose. Ajouter deux octets peut déborder. XORing deux octets ne peut pas. – dan04

0

Il semble que dans les spécifications du langage C#, il est défini pour entier et à long http://msdn.microsoft.com/en-us/library/aa691307%28v=VS.71%29.aspx

Alors, qu'est-ce qui se passe réellement est que le compilateur jette opérandes octets int implicitement parce qu'il n'y a perte de données de cette façon. Mais le résultat (qui est int) ne peut pas être édité sans perte de données (implicitement). Donc, vous devez dire explicitement au compilateur que vous savez ce que vous faites!

+0

Ce qui serait utile dans le scénario mentionné par l'article lié serait que le compilateur fudge la surcharge de l'opérateur en fonction de la valeur de retour, ou bien que '~ b' donne une valeur qui n'est pas un type entier mais qui peut être convertie en de taille appropriée au besoin. Une telle approche pourrait aider avec des cas comme 'longVal & = ~ intVal;', où le résultat de '~' devrait vraiment être 'long'. – supercat

0

En ce qui concerne pourquoi les deux octets doivent être convertis en ints pour faire le XOR? Si vous voulez vous y intéresser, le 12.1.2 de la spécification CLI (Partition I) décrit le fait que, sur la pile d'évaluation, seulement int ou long peut exister. Tous les types intégraux plus courts doivent être développés pendant l'évaluation.

Malheureusement, je n'arrive pas à trouver un lien approprié directement à la CLI Spec - J'ai une copie locale en format PDF, mais je ne me souviens pas d'où je l'ai trouvée.

-1

FWIW octet a = 25; octet b = 60; a = a^b; ne fonctionne pas. Cependant, octet a = 25; octet b = 60; a^= b; fonctionne.

Questions connexes