Преобразование логического числа в целое число возвращает -1 для истины?

Я работаю с некоторым кодом VB.NET, который, кажется, преобразует логическое значение в целое число, используя CInt(myBoolean), Странная вещь в том, что она возвращает -1, если значение истинно. Например:

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

Это распространено в других языках?

Я думал, что логическое значение будет 1, если истина и 0, если ложь. Кроме того, есть ли способ заставить Visual Basic присваивать 1 значение true вместо назначения -1?

11 ответов

Решение

Как правило, значение false представлено 0, а значение true представлено любым целым значением, отличным от 0. Конкретные значения true и false (среди прочих) - это те вещи, на которые вы не должны полагаться - они могут потенциально зависеть от реализации. Я не уверен, что вы пытаетесь сделать, но, вероятно, лучше не полагаться на True или же False иметь какие-либо конкретные целочисленные значения, если вам не нужно.

Лучшее объяснение, которое я мог найти для специфического поведения VB, приходит из Википедии:

Логическая константа True имеет числовое значение -1. Это связано с тем, что логический тип данных хранится как 16-разрядное целое число со знаком. В этой конструкции -1 оценивает до 16 двоичных 1 (логическое значение True), а 0 как 16 0 (логическое значение False). Это очевидно при выполнении операции Not для 16-разрядного целого числа со знаком 0, которое будет возвращать целое значение -1, другими словами True = Not False. Эта внутренняя функциональность становится особенно полезной при выполнении логических операций над отдельными битами целого числа, такими как And, Or, Xor и Not.[4] Это определение True также согласуется с BASIC с начала реализации Microsoft BASIC начала 1970-х годов и также связано с характеристиками инструкций процессора в то время.

Обходной путь для вашего первоначального использования будет:

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

Это вернет 0.

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

Это вернет 1.

Это похоже на гочу, и я не знаю других примеров такого поведения.

http://msdn.microsoft.com/en-us/library/ae382yt8.aspx определяет это поведение с помощью замечания типа "Не делай этого, mkay". Сделайте запись дальше внизу:

Конверсия в Каркасе

Метод ToInt32 класса Convert в пространстве имен System преобразует True в +1.

Если вам необходимо преобразовать логическое значение в числовой тип данных, будьте осторожны с тем, какой метод преобразования вы используете.

Документация MSDN предоставляет некоторые ценные сведения:

Булевы значения не хранятся в виде чисел, и сохраненные значения не предназначены для того, чтобы быть эквивалентными числам. Вы никогда не должны писать код, который полагается на эквивалентные числовые значения для True и False. По возможности, вы должны ограничивать использование логических переменных логическими значениями, для которых они предназначены.

У меня была такая же проблема и использовал Math.Abs функция на результат:)

Во многих версиях BASIC в 1970-х и 1980-х годах применялась побитовая арифметика с их AND а также OR операторы и сделали истинные условные выражения, оцениваемые в -1 (что было значением "all-bits-set"). Я не совсем уверен, почему было принято решение, чтобы истинные условные выражения оценивались как значение, установленное во всех битах; возможность использовать AND маскировать целое число против условного выражения, возможно, было быстрее, чем умножение, но, учитывая тогда внутреннюю механику интерпретаторов, разница была бы незначительной.

В любом случае, первые версии BASIC, которые Microsoft выпустила для ПК, следовали той традиции, когда истинные условные выражения оценивались в -1 (набор всех битов); поскольку QuickBASIC, в свою очередь, должен был быть совместим с ними, а Visual Basic должен был быть совместим с QuickBASIC, они использовали то же представление. Хотя.Net распознает целые и логические значения как разные типы, vb.net хотел предложить путь миграции для программ VB6, которые могли бы полагаться на старое поведение. При "Option Strict Off" VB.Net неявно преобразует логическое значение True в целое число -1; в то время как большинство программистов используют Option Strict OnСмущает поведение CInt() отличаются от неявного преобразования поведения.

Я проверил это и получил следующие результаты:

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

Это приведет к:

1
1

Я надеюсь, что это доказывает, что все True значения внутри.NET всегда одинаковы. Причина проста: все члены.NET должны общаться друг с другом. Было бы странно, если object.Equals(trueFromCSharp, trueFromVB) приведет к ложному (как будет trueFromCSharp == trueFromVB).

CInt это просто функция, которая будет конвертировать True в -1, Другая функция Int вернусь 1, Но это конвертеры и ничего не говорят о двоичных значениях.

У меня была та же проблема с MySQL, так как у нее нет логического типа, а только tinyint(1).

Мое решение состояло в том, чтобы написать функцию конвертера, чтобы убедиться, что значения правильны, прежде чем вставить их в базу данных

        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

Я надеюсь, что это может помочь другим работать с логическими значениями внутри VB.NET. Так же, как лучший способ написать VB.NET, который написал Роджер:

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

Я могу немного опоздать, но вот простой обходной путь, чтобы получить типичный 1 для True и 0 для False.

Умножьте логическое значение на -1 следующим образом:

      CInt(True) * -1
CInt(False) * -1

Который затем возвращает

1
0

Я обнаружил, что других ответов не хватает для конкретного сценария VBA, с которым я работал. Это не проверено в VB.NET.

Я хотел взять любое заданное число, которое было <> 0, и сделать его 1, и сохранить 0 как 0 в одной строке кода без оператора If. То, как я это сделал, чего я не видел в других данных ответах, было:

      Abs(CBool(iCount))

CBool()преобразует заданное число ( iCountв приведенном выше примере) в логическое значение, сужая возможные результаты до двух значений; со значением -1и со значением .

Abs()затем принимает абсолютное значение (без отрицательных значений) логического значения для возврата Falseи для True.

На практике следующий возврат 0:

      Abs(CBool(0))
Abs(False)

И следующее возвращение 1:

      Abs(CBool(1))
Abs(CBool(-1))
Abs(CBool(-38473))
Abs(CBool(358677))
Abs(True)

Я надеюсь, что это будет полезно для всех, кто играет с конкретными сценариями, подобными этому.

Другие вопросы по тегам