Неправильная операция с числом с плавающей точкой

Я продолжаю получать эту ошибку «Недопустимая операция с плавающей запятой».

Я на Делфи 7.

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
TlHelp32, Dialogs, StdCtrls, ExtCtrls, Buttons, ComCtrls;

var //global
PHandle, cancel, bytes, scantype: integer;

...

procedure Tmain.scanbtnClick(Sender: TObject);
    var max, address: Integer;
    floatinput, floatinput1, floatinput2, datafloat: Real;
    x: cardinal;
    itm: TListItem;
begin

  floatinput := StrToFloat(Trim(valueinput.Text));
  floatinput1 := StrToFloat(Trim(valueinput1.Text));
  floatinput2 := StrToFloat(Trim(valueinput2.Text));

  if floatinput2 < floatinput1 then
  begin
    floatinput1 := floatinput1 + floatinput2;
    floatinput2 := floatinput1 - floatinput2;
    floatinput1 := floatinput1 - floatinput2;
  end;

  result.Show;

  x := 0;
  address := 0;

  result.resultlist.Clear;

  repeat
    Application.ProcessMessages;
    statusbar1.Panels.Items[1].Text := 'Searching... ' + IntToStr(address * 100 div max) + '% (' + IntToStr(address div bytes) + ' out of ' + IntToStr(max div bytes) + ').';

    if ReadprocessMemory(PHandle, Ptr(address), @datafloat, bytes, x) then
      begin
        if (x > 0) then
        begin
          if scantype = 0 then
          begin
            if datafloat = floatinput then             //error here
            begin
              itm := result.resultlist.Items.Add;
              itm.Caption := '0x' + IntToHex(address,8);
              itm.SubItems.Add(FormatFloat('0.0#########', datafloat));
            end;
          end;
          if scantype = 1 then
          begin
            if datafloat > floatinput              //also here
            then begin
              itm := result.resultlist.Items.Add;
              itm.Caption := '0x' + IntToHex(address,8);
              itm.SubItems.Add(FormatFloat('0.0#########', datafloat));
            end;
          end;
          if scantype = 2 then
          begin
            if datafloat < floatinput     //here too
            then begin
              itm := result.resultlist.Items.Add;
              itm.Caption := '0x' + IntToHex(address,8);
              itm.SubItems.Add(FormatFloat('0.0#########', datafloat));
            end;
          end;
          if scantype = 2 then
          begin
            if (dataint <= intinput2) and (dataint >= intinput1)    //even here
            then begin
              itm := result.resultlist.Items.Add;
              itm.Caption := '0x' + IntToHex(address,8);
              itm.SubItems.Add(FormatFloat('0.0#########', datafloat));
            end;
          end;

        end;
      end;

    if x <> 0
    then address := address + x
    else address := address + bytes;

  until (address >= Max) or (cancel = 1);

end;

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

Это не ReadMemory, потому что этот небольшой фрагмент кода находится в цикле while и возвращает несколько допустимых значений, прежде чем столкнуться с этой ошибкой.

Что я должен делать?

Заранее спасибо.


person D3X    schedule 26.11.2015    source источник
comment
Какой тип данных у datafloat? Вы сравниваете его с вариантом (Null), но вариант не является типом, совместимым с ReadProcessMemory. Вы имеете в виду использовать Double?   -  person Gerry Coll    schedule 27.11.2015
comment
Код, который вы разместили, не будет компилироваться, поскольку единственное допустимое использование NULL в Delphi — это использование вариантов. Опубликуйте полный фактический код, который вы используете. Просить нас отладить код, который на самом деле не является вашим кодом, — пустая трата как вашего, так и нашего времени. Опубликуйте компилируемый MCVE, демонстрирующий проблему, если вам нужна помощь здесь.   -  person Ken White    schedule 27.11.2015
comment
Массив данных @GerryColl реален. Не могли бы вы объяснить мне, что именно происходит, когда я пытаюсь сравнить значение с нулем?   -  person D3X    schedule 27.11.2015
comment
@KenWhite полный код на самом деле довольно большой, и нет необходимости заполнять тему вещами, которые, вероятно, не будут иметь отношения к проблеме. Какую информацию я могу вам дать, чтобы вы могли видеть яснее?   -  person D3X    schedule 27.11.2015
comment
Затем сократите его до минимального кода, необходимого для демонстрации проблемы. Мы не можем отлаживать код, который не видим, или код, который не компилируется. Как я уже просил, опубликуйте MCVE, который мы можем использовать.   -  person Ken White    schedule 27.11.2015
comment
@KenWhite - он скомпилируется, но на самом деле не будет работать должным образом. Также D3X, возможно, (повторно) объявил null как константу, скрывая объявление в Variants (при условии, что D6+)   -  person Gerry Coll    schedule 27.11.2015
comment
@ D3X - Null используется для вариантов, а не для простых типов данных. real не может быть равно нулю или даже Nil, если на то пошло, это не похоже на типы, допускающие значение null, в .net.   -  person Gerry Coll    schedule 27.11.2015
comment
@GerryColl, наверное, он всегда возвращал true .. но я уже исправил это.   -  person D3X    schedule 27.11.2015
comment
@KenWhite Добавил больше информации в тему..   -  person D3X    schedule 27.11.2015
comment
@GerryColl: я понятия не имею, что объявил (или не объявил) OP, поскольку эта информация не содержится в вопросе. Спекуляции о том, что мог или мог сделать ОП, бессмысленны; опубликованный код должен представлять MCVE, который мы можем скомпилировать для устранения неполадок или отладки. Без этого любые предположения о том, что может быть, а что не может быть, — это просто шум и беспорядок.   -  person Ken White    schedule 27.11.2015
comment
Ваше редактирование улучшает ситуацию, но это все еще не MCVE. Нет никаких указаний на то, что содержит значение многих переменных, есть зависимости, которые недоступны (result и Tmain) и не имеют отношения к проблеме, другой код пользовательского интерфейса (список и редактирование), который также не имеет смысла для вопроса . Консольное приложение без содержимого пользовательского интерфейса было бы значительно лучше. Кроме того, почему вы просто произвольно ReadProcessMemory вводите значения в элементы управления редактированием, а затем делаете предположение, что то, что вы читаете, будет значением с плавающей запятой?   -  person Ken White    schedule 27.11.2015


Ответы (1)


Мы видим две потенциальные проблемы с кодом.

Прежде всего, вы не проверяете возвращаемое значение ReadProcessMemory. Этот вызов может завершиться неудачей по разным причинам. Поскольку вы не проверяете наличие ошибок, у вас нет возможности узнать, был ли вызов функции успешным. Всегда проверяйте вызовы API на успешность. Прочтите документы на MSDN, чтобы узнать, как это сделать. Обычно это включает проверку возвращаемого функцией значения, как в данном случае. Если функция завершается ошибкой, то переменная с плавающей запятой может содержать неинициализированные данные, что может привести к ошибке.

Другая проблема заключается в том, что datafloat заполняется чтением байтов из другого процесса. Если эти байты не представляют допустимое значение с плавающей запятой, то при попытке оперировать с этим значением будет возбуждено исключение. Не все битовые комбинации представляют допустимые значения с плавающей запятой. Например, вы могли столкнуться с сигнальным значением NaN. Возможно, вам следует сравнивать с CompareMem, учитывая, что вы, кажется, читаете произвольную память, что выглядит как попытка реконструировать какую-то другую программу. Тестирование побитовым сравнением позволит избежать риска загрузки недопустимых значений в регистры с плавающей запятой.

Наконец, я не уверен, что вы подразумеваете под тестированием значения с плавающей запятой против null, что бы ни было null. Значения с плавающей запятой не могут принимать значения NULL. Очень вероятно, что у вас есть существенное недопонимание.

person David Heffernan    schedule 26.11.2015
comment
Итак, я изменил свой код, и теперь я продолжаю только в том случае, если результат ReadProcessMemory верен, а затем я проверяю, равно ли число прочитанных байтов › 0, и хотя я не совсем понимаю, почему, процедура comparemem сработала, но что, если я хочу знать, если datafloat › floatinput? Разве я не могу сравнить два реальных значения? - person D3X; 27.11.2015
comment
На самом деле.. нет. CompareMem возвращает false, даже когда он должен возвращать true, когда я использую обычное сравнение, он возвращает только те значения, которые должен, но через некоторое время всегда появляется эта ошибка. - person D3X; 27.11.2015
comment
Хорошо, я исправил это, ваш ответ был действительно полезен. Что я сделал, так это объявил «Math» в использовании, а затем проверил, не является ли «datafloat» NaN, используя процедуру IsNan, спасибо. - person D3X; 27.11.2015
comment
CompareMem будет работать, если вы используете его правильно. Если вы хотите выполнить сравнение, отличное от равенства, для ненулевых конечных значений, это сработает. Использование IsNaN — хороший вариант. Все дело в том, что вы оперируете ценностями, происхождение которых вам неизвестно. - person David Heffernan; 27.11.2015