ti-enxame.com

Converter um booleano para um número inteiro retorna -1 como verdadeiro?

Estou trabalhando com algum código VB.NET que parece estar lançando um valor booleano para um número inteiro usando CInt(myBoolean). O estranho é que ele retorna -1 se o valor for verdadeiro. Por exemplo:

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

Isso é comum em outros idiomas?

Eu pensei que um booleano seria 1 se verdadeiro e 0 se falso. Além disso, existe uma maneira de fazer o Visual Basic atribuir 1 como true em vez de atribuir -1?

40
Barlow Tucker

Normalmente, um valor de false é representado por 0 e um valor de true é representado por qualquer valor inteiro diferente de 0. O valor específico para true e false (entre outros) são coisas nas quais você não deve confiar - elas podem ser potencialmente específicas da implementação. Não tenho certeza do que você está tentando fazer, mas provavelmente seria melhor não confiar em True ou False com valores inteiros específicos, a menos que seja absolutamente necessário.

A melhor explicação que eu poderia encontrar para o comportamento específico do VB vem de Wikipedia :

A constante booleana True tem valor numérico -1. Isso ocorre porque o tipo de dados booleano é armazenado como um número inteiro assinado de 16 bits. Nesta construção, -1 avalia 16 binários 1s (o valor booleano True) e 0 como 16 0s (o valor booleano False). Isso é aparente ao executar uma operação Not em um valor inteiro assinado de 16 bits 0, que retornará o valor inteiro -1, ou seja, True = Not False. Essa funcionalidade inerente se torna especialmente útil ao executar operações lógicas nos bits individuais de um número inteiro como And, Or, Xor e Not. [4] Essa definição de True também é consistente com o BASIC desde a implementação do Microsoft BASIC do início dos anos 70 e também está relacionada às características das instruções da CPU no momento.

38
Thomas Owens

Uma solução alternativa para seu uso inicial seria:

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

Isso retornará um 0.

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

Isso retornará 1.

13
Michael Eakins

Parece uma pegadinha, e não conheço outros exemplos desse comportamento.

http://msdn.Microsoft.com/en-us/library/ae382yt8.aspx especifica esse comportamento, com uma observação "Não faça isso, mkay". Anote mais abaixo:

Conversão no quadro

O método ToInt32 da classe Convert no espaço para nome do sistema converte True em +1.

Se você precisar converter um valor booleano em um tipo de dados numérico, tenha cuidado com o método de conversão usado.

9
Martijn

O documentação do MSDN fornece algumas informações valiosas:

Os valores booleanos não são armazenados como números e os valores armazenados não devem ser equivalentes a números. Você nunca deve escrever um código que dependa de valores numéricos equivalentes para True e False. Sempre que possível, você deve restringir o uso de variáveis ​​booleanas aos valores lógicos para os quais eles foram projetados.

5
dbasnett

Eu tive o mesmo problema e usei Math.Abs função no resultado :)

5
marco

Muitas versões do BASIC nas décadas de 1970 e 1980 implementaram aritmética bit a bit com seus operadores AND e OR e fizeram com que expressões condicionais verdadeiras fossem avaliadas como -1 (que era o "conjunto de todos os bits"). " valor). Não sei exatamente por que foi tomada a decisão de ter expressões condicionais verdadeiras avaliadas para um valor definido por todos os bits; poder usar AND para mascarar um número inteiro contra uma expressão condicional pode ter sido mais rápido do que multiplicado, mas, dada a mecânica interna dos intérpretes, a diferença teria sido pequena.

De qualquer forma, as primeiras versões do BASIC que a Microsoft produziu para o PC seguiram a tradição de ter condicionais verdadeiros avaliados como -1 (conjunto de todos os bits); como o QuickBASIC deveria, por sua vez, ser compatível com eles e o Visual Basic deveria ser compatível com o QuickBASIC, eles usavam a mesma representação. Embora o .Net reconheça números inteiros e booleanos como tipos diferentes, o vb.net desejava oferecer um caminho de migração para programas VB6 que podem depender do comportamento antigo. Com "Option Strict Off", o VB.Net converterá implicitamente um valor booleano de True em um número inteiro -1; enquanto a maioria dos programadores usa Option Strict On, é confuso ter o comportamento de CInt() diferente do comportamento implícito de conversão.

4
supercat

Eu testei e obtive os seguintes resultados:

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);
}

Isso resultará em:

1
1

Espero que isso prove que todos os valores de True dentro do .NET são sempre os mesmos. O motivo é simples: todos os membros do .NET precisam se comunicar. Seria estranho se object.Equals(trueFromCSharp, trueFromVB) resultasse em false (como será trueFromCSharp == trueFromVB).

CInt é apenas uma função que irá converter True em -1. Outra função Int retornará 1. Mas estes são conversores e não dizem nada sobre os valores binários.

3
Martin Mulder

Eu estou tendo o mesmo problema com o MySQL, pois este não possui um tipo booleano, apenas um tinyint (1).

Minha solução foi escrever uma função de conversor para garantir que os valores estejam corretos antes de inseri-los no banco de dados

        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

Espero que isso possa ajudar outras pessoas a trabalhar com booleanos dentro do VB.NET. Apenas como uma maneira melhor de escrever o VB.NET que Roger escreveu:

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