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

39

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

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

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

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

Теги:
boolean

9 ответов

36
Лучший ответ

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

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

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

  • 2
    Я только что проверил эту предпосылку. Логическое значение в VB.NET не равно -1 , оно равно только 1 . Я проверил это, создав структуру с двумя перекрывающимися полями, используя FieldOffsetAttribute. Таким образом, вы можете увидеть точное двоичное значение логического значения. CInt - это просто обращение. Ссылка на старую документацию не очень помогает, я думаю.
  • 2
    Я передал True в функцию, которая приняла целое число и получила значение -1 в VB.NET. В статье, посвященной ссылкам Martjin ( msdn.microsoft.com/en-us/library/ae382yt8.aspx ), похоже, что преобразование логического значения определяет, какое целое значение вы получите.
11

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

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

Это вернет 0.

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

Это вернет 1.

9

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

http://msdn.microsoft.com/en-us/library/ae382yt8.aspx указывает это поведение, с этим замечанием "Не делайте этого, mkay". Делайте заметку ниже:

Конверсия в Framework

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

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

4

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

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

4

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

4

документация MSDN дает некоторую ценную информацию:

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

3

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

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) приведет к false (как и trueFromCSharp == trueFromVB).

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

1

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

Public Function BoolToMySql(bVal As Boolean) As Integer
   return  If(bVal, 1, 0)
End Function
  • 0
    Я считаю, что должно быть IIf , а не If .... так: return IIf(bVal, 1, 0)
1

У меня была такая же проблема с MySQL, поскольку у этого типа не существует типа Boolean только 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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню