web-dev-qa-db-fra.com

La conversion d'un booléen en un entier renvoie -1 pour vrai?

Je travaille avec du code VB.NET qui semble convertir une valeur booléenne en un entier en utilisant CInt(myBoolean). La chose étrange qui se produit est qu'elle renvoie -1 si la valeur est vraie. Par exemple:

CInt(True)  // returns -1
CInt(False) // returns 0

Est-ce courant dans d'autres langues?

Je pensais qu'un booléen serait 1 si vrai et 0 si faux. De plus, existe-t-il un moyen de faire en sorte que Visual Basic affecte 1 à true au lieu d'affecter -1?

40
Barlow Tucker

En règle générale, une valeur false est représentée par 0 et une valeur true est représentée par une valeur entière non-0. La valeur spécifique de true et false (entre autres) sont des choses sur lesquelles vous ne devriez pas vous fier - elles peuvent potentiellement être spécifiques à l'implémentation. Je ne suis pas sûr de ce que vous essayez de faire, mais il serait probablement préférable de ne pas compter sur True ou False ayant des valeurs entières spécifiques à moins que vous ne deviez absolument le faire.

La meilleure explication que j'ai pu trouver pour le comportement spécifique de VB vient de Wikipedia :

La constante booléenne True a une valeur numérique −1. Cela est dû au fait que le type de données booléen est stocké sous la forme d'un entier signé 16 bits. Dans cette construction, -1 correspond à 16 1 binaires (la valeur booléenne True) et 0 à 16 0 (la valeur booléenne False). Cela apparaît lors de l'exécution d'une opération Not sur une valeur entière signée 16 bits 0 qui retournera la valeur entière -1, en d'autres termes True = Not False. Cette fonctionnalité inhérente devient particulièrement utile lors de l'exécution d'opérations logiques sur les bits individuels d'un entier tel que And, Or, Xor et Not. [4] Cette définition de True est également cohérente avec BASIC depuis l'implémentation Microsoft BASIC au début des années 1970 et est également liée aux caractéristiques des instructions CPU à l'époque.

38
Thomas Owens

Une solution de contournement pour votre utilisation initiale serait:

 Dim i As Integer = CInt(Int(False))

Cela retournera un 0.

 Dim i As Integer = CInt(Int(True))

Cela renverra un 1.

13
Michael Eakins

Cela ressemble à un piège, et je ne connais aucun autre exemple de ce comportement.

http://msdn.Microsoft.com/en-us/library/ae382yt8.aspx spécifie ce comportement, avec une remarque sorta "Don't do that, mkay" avec. Notez plus bas:

Conversion dans le cadre

La méthode ToInt32 de la classe Convert dans l'espace de noms System convertit True en +1.

Si vous devez convertir une valeur booléenne en un type de données numérique, faites attention à la méthode de conversion que vous utilisez.

9
Martijn

documentation MSDN fournit des informations précieuses:

Les valeurs booléennes ne sont pas stockées sous forme de nombres et les valeurs stockées ne sont pas censées être équivalentes à des nombres. Vous ne devez jamais écrire de code reposant sur des valeurs numériques équivalentes pour True et False. Dans la mesure du possible, vous devez limiter l'utilisation des variables booléennes aux valeurs logiques pour lesquelles elles sont conçues.

5
dbasnett

J'ai eu le même problème et j'ai utilisé Math.Abs fonction sur le résultat :)

5
marco

De nombreuses versions de BASIC dans les années 1970 et 1980 ont implémenté l'arithmétique bit à bit avec leurs opérateurs AND et OR, et ont fait en sorte que les vraies expressions conditionnelles soient évaluées à -1 (qui était "l'ensemble de bits") " valeur). Je ne sais pas exactement pourquoi la décision a été prise d'avoir de vraies expressions conditionnelles évaluées en une valeur d'ensemble de bits; avoir pu utiliser AND pour masquer un entier contre une expression conditionnelle aurait pu être plus rapide que de multiplier, mais étant donné la mécanique interne des interprètes, la différence aurait été légère.

Dans tous les cas, les premières versions de BASIC produites par Microsoft pour le PC ont suivi dans cette tradition d'avoir de vraies conditions évaluées à -1 (ensemble de bits); comme QuickBASIC était à son tour censé être compatible avec ceux-ci, et Visual Basic était censé être compatible avec QuickBASIC, ils ont utilisé la même représentation. Bien que .Net reconnaisse les entiers et les booléens comme des types différents, vb.net voulait offrir un chemin de migration pour les programmes VB6 qui pourraient s'appuyer sur l'ancien comportement. Avec "Option Strict Off", VB.Net convertira implicitement une valeur booléenne True en un entier -1; alors que la plupart des programmeurs utilisent Option Strict On, il peut être déroutant que le comportement de CInt() diffère du comportement de conversion implicite.

4
supercat

Je l'ai testé et j'ai obtenu les résultats suivants:

Public Module BooleanTest
Public Function GetTrue() As Boolean
    GetTrue = True
End Function
End Module

...

[StructLayout(LayoutKind.Explicit)]
struct MyStruct
{
    [FieldOffset(0)]
    public bool MyBool;
    [FieldOffset(0)]
    public int MyInt32;
}

static void Main(string[] args)
{
    MyStruct b1, b2;
    b1.MyInt32 = 0;
    b2.MyInt32 = 0;
    b1.MyBool = BooleanTest.BooleanTest.GetTrue();
    b2.MyBool = true;
    Console.WriteLine(b1.MyInt32);
    Console.WriteLine(b2.MyInt32);
}

Cela se traduira par:

1
1

J'espère que cela prouve que toutes les valeurs de True dans .NET sont toujours les mêmes. La raison est simple: tous les membres de .NET doivent communiquer entre eux. Ce serait bizarre si object.Equals(trueFromCSharp, trueFromVB) se traduisait par false (tout comme trueFromCSharp == trueFromVB).

CInt est juste une fonction qui convertira True en -1. Une autre fonction Int renverra 1. Mais ce sont des convertisseurs, et ne disent rien sur les valeurs binaires.

3
Martin Mulder

J'ai eu le même problème avec MySQL car cela n'a pas de type booléen seulement un tinyint (1).

Ma solution était d'écrire une fonction de convertisseur pour s'assurer que les valeurs sont correctes avant de les insérer dans la base de données

        Public Function BoolToMySql(bVal As Boolean) As Integer
            Dim retVal As Integer
            If bVal = True Then
                retVal = 1
            Else
                retVal = 0
            End If
                 BoolToMySql = retVal
        End Function
2
Roger

J'espère que cela peut aider les autres à travailler avec des booléens dans VB.NET. Tout comme une meilleure façon d'écrire le VB.NET que Roger a écrit:

Public Function BoolToMySql(bVal As Boolean) As Integer
   return  If(bVal, 1, 0)
End Function
1
John Grabauskas