2009-10-14 5 views
4

J'ai trouvé une situation étrange dans le compilateur C#. Pourquoi la distribution ci-dessous est requise?C# Bitwise OR doit être casté avec des octets * parfois *

using System; 

class Program 
{ 
    private const byte BIT_ZERO_SET = 1; 
    private const byte BIT_ONE_SET = 2; 
    private const byte BIT_TWO_SET = 4; 

    static void Main(string[] args) 
    { 
     byte b = BIT_ZERO_SET | BIT_ONE_SET; 
     Console.WriteLine(b); 

     //Does not compile, says needs to cast to int. 
     //b = b | BIT_TWO_SET; 

     //Compiles...ugly 
     b = (byte)(b | BIT_TWO_SET); 
     Console.WriteLine(b); 

     Console.WriteLine("Press enter."); 
     Console.ReadLine();  
    } 
} 

Merci.

Répondre

6

est suspect que la ligne:

byte b = BIT_ZERO_SET | BIT_ONE_SET; 

est en fait traité par le compilateur C# en une assignation d'une valeur constante à b, plutôt qu'une opération de bits - il peut le faire parce que le côté droit de la expression est entièrement définie au moment de la compilation.

La ligne:

//b = b | BIT_TWO_SET; 

n'a pas compilé parce que l'opérateur sage bit ou la promotion de ses éléments et évalue à un int, pas un octet. Comme il implique une valeur d'exécution (b), il ne peut pas être compilé en une affectation constante comme la ligne précédente, et nécessite d'être casté.

+0

Cela a du sens ... – Nate

+0

+1, Oui, le compilateur calculera des expressions constantes lors de la compilation. Ce qui explique pourquoi la première affectation ne donne pas d'erreur. –

+0

@Godeke: Comment dites-vous quelque chose de différent de ce qu'il est? Il dit que la valeur résultante d'un OU «bit» sur un «byte» est un int. –

7

Il est certainement étrange, mais ce qui se passe, est le résultat de b|BIT_TWO_SET est un nombre entier. Cela fonctionne: b = (byte)(b | BIT_TWO_SET); parce que le résultat est un int dans ce cas.

En outre, vous pouvez remplacer cette ligne par: b |= BIT_TWO_SET; qui fonctionne.

+0

Je ne savais pas qu'il y avait un | =. Merci! – Nate

+0

'x | = y' et' x & = ~ y' sont vos amis pour la manipulation de bits. –

2
 b = (byte)(b | BIT_TWO_SET); 

est tout ce que vous avez besoin de convertir pour le compiler, au moins dans Visual Studio 2008 contre 2.0. Il semble que | promeut l'octet à int et vous devez le rétrograder à la main.

Yep ... un passage rapide après le standard montre que | renvoie int (ou uint ou long ou ulong).

+0

Oui, j'ai changé de sujet après que je m'en suis rendu compte. Merci. – Nate

0

Au lieu d'utiliser

b = b | BIT_TWO_SET; 

utiliser ceci:

b |= BIT_TWO_SET; 

hein drôle.

12

Les différentes réponses ici sont généralement correctes, mais ont un tas de faits différents répartis partout. Les points pertinents sont:

1) Le résultat de l'octet | octet est un int, car il n'y a pas | opérateur défini sur octets.

2) Les calculs impliquant uniquement des constantes intégrales de compilation sont traités comme une arithmétique «vérifiée»; c'est-à-dire que le compilateur vérifie que le résultat constant ne déborde pas, et ainsi de suite. Une conséquence agréable de ce fait est qu'une affectation d'un entier constant à la compilation à une variable ou à une constante d'un type plus petit vérifie automatiquement que l'entier constant s'adapte au type plus petit. Si c'est le cas, l'affectation est autorisée sans un cast explicite. Si ce n'est pas le cas, une erreur de compilation survient. (Utilisez l'expression "non cochée" si vous voulez surcharger ce comportement.)

3) Les affectations d'expressions non constantes de type int à byte nécessitent des conversions, car le compilateur n'a aucun moyen de savoir si le résultat correspond vraiment l'octet.4) Les opérateurs d'affectation composés insèrent automatiquement une distribution dans le type d'opérande dans le cadre de leur opération, précisément pour que des expressions comme b | = fonctionnent comme prévu. Ces quatre faits devraient expliquer tout le comportement que vous avez souligné.

Questions connexes