четверг, 27 июня 2019 г.

Почему функция GetVersion сообщает основную версию в младшем байте и младшую версию в старшем байте?

Это перевод Why does the Get­Version function report the major version in the low-order byte, and the minor version in the high-order byte? Автор: Реймонд Чен.

Лора Батлер задаёт вопрос: кому в голову пришла идея возвращать основную (major) версию в младшем байте, а младшую (minor) версию - в старшем байте функции GetVersion. Надо же делать наоборот: нужно возвращать основную версию в старшем байте и младшую версию в младшем байте, чтобы вы могли делать такое:
if ГипотетическаяУлучшеннаяGetVersion >= $030A then
begin
  // версия минимум 3.10
end;
Вместо этого сейчас основная версия возвращается в младшем байте, а младшая версия - в старшем байте, поэтому версия 3.10 возвращается как значение $0A03, что приводит к таким ошибкам:
if GetVersion >= $0A03 then
begin
  // неверная проверка на версию ≥ 3.10
end;
Почему номер версии возвращается таким странным образом?

Мысленно перенеситесь назад во времени во времена MS-DOS.

MS-DOS имеет системный вызов Get Version и он возвращает версию операционной системы тем же способом (в обратном порядке - с основной версией в младшем байте и второстепенной версией в старшем байте).

Идея заключалась в том, что программы почти всегда будут проверять только основную (major) версию - потому что вам нужно проверять младшую (minor) версию только если вам нужно проверить на какую-либо функцию, добавленную во вспомогательной версии. Но, по определению, второстепенные версии не добавляют много функций (верно, ведь?), поэтому проверка на минорную версию должна быть очень редкой.

В ту эпоху программы писались на ассемблере, и именно эта деталь проливает свет на столь необычный формат номера версии.

На 8086 16-разрядный регистр AX может рассматриваться как 16-разрядное значение или как два 8-разрядных значения. Если вы рассматриваете его как два 8-битных значения, то старший байт называется AH, а младший байт называется AL.

Инструкции 8086 для сравнения значений в этих регистрах кодируются следующим образом:

ИнструкцияМашинный код
CMP AL, $033C 03
CMP AH, $0380 FC 03

Поскольку почти все будут сравнивать только основную версию - нам следует сделать эту проверку наиболее эффективной. Следовательно, нам нужно выбрать вариант с регистром AL. Использование регистра AL (младшего байта) для хранения основной версии позволяет короче записывать проверки версий, чем если бы мы использовали регистр AH.

Мы только что сэкономили целый байт!

IBM PC поставлялся в двух конфигурациях памяти: с 16 Кб и 64 Кб. Если вы выложили бо́льшие деньги за 64-килобайтную версию, то этот один байт составляет 0.0015% от общего объёма памяти. Если мы промасштабируем до современной системы с 8 Гб ОЗУ, то выбор такого формата возврата номера версии экономит нам 128 Кб.

Windows же унаследовала схему нумерации версий из MS-DOS, и поэтому функция GetVersion возвращает основную и младшую версии в обратном порядке.

1 комментарий:

  1. Не мог найти Вашу почту поэтому написал сюда.Помогите пожалуйста!
    Нужно залить большую таблицу, около миллиона строк в БД Firebird 2.5
    Пробую импортировать так:
    procedure XlsToStringGrid(AGrid: TStringGrid; AXLSFile: string);
    const
    xlCellTypeLastCell = $0000000B;
    var
    XLApp, Sheet: OLEVariant;
    RangeMatrix: Variant;
    x, y, k, r: Integer;
    begin
    XLApp := CreateOleObject('Excel.Application');
    try
    xlapp.Visible := False;
    XLApp.Workbooks.Open(AXLSFile);
    Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];
    Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
    x := XLApp.ActiveCell.Row;
    y := XLApp.ActiveCell.Column; AGrid.RowCount := x;
    AGrid.ColCount := y;
    {rcounts:=x;}
    RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value;
    k := 1;
    repeat
    for r := 1 to y do AGrid.Cells[(r - 1), (k - 1)] := RangeMatrix[K, R];
    Inc(k, 1);
    AGrid.RowCount := k + 1;
    until k > x;
    RangeMatrix := Unassigned;
    finally
    if not VarIsEmpty(XLApp) then
    begin
    xlapp.application.screenupdating:=true;
    xlapp.application.enableevents:=true;
    xlapp.application.interactive:=true;
    xlapp.application.displayalerts:=true;
    XLApp.ActiveWorkBook.Close;
    XLAPP := Unassigned;
    Sheet := Unassigned;
    end;
    end;
    end;

    На строке RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value;
    вылетает такая ошибка: EOleSysError Недостаточно памяти для завершения операции!
    RAM 8 Gb на моем ПК, мониторил память и во время вылета было 4,4 Гб свободно.
    Как побороть эту проблему?

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.

Примечание. Отправлять комментарии могут только участники этого блога.