Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Форум группы: delphi > Какие ошибки могут быть в коде?


Автор: THandle 11.12.2009, 22:41
Всем привет.

Имеется к примеру вот такая процедурка(взято абстрактно):

Код

procedure SomeProc(const A, B: Integer; var Result: Integer);
begin
  Result := A + B;
end;


Какие в ней вообще могут возникнуть ошибки? smile

С помощью одного моего начинающего товарища мне удалось выявить по крайней мере возникновение одного типа ошибки в данном коде.
Углубимся в историю: я дал ему модуль с какими-то функциями. Он вызывал их, и одну, решив что так для него будет удобнее вызвал так, что потом жаловался мне в том что мой модуль не правильно работает smile

Предложения? smile

Автор: Rrader 12.12.2009, 17:35
Вот так можно smile 
Код

var
  R: Integer;
begin
  SomeProc(MaxInt, MaxInt, R);
  ...

Автор: Akella 12.12.2009, 19:01
Цитата(Rrader @  12.12.2009,  17:35 Найти цитируемый пост)
Вот так можно

А по другому и нельзя. Вопрос в том, какие могут быть ошибки?

Автор: THandle 12.12.2009, 19:17
У меня смысл ошибки заключался в том, что человек вызвал процедуру следующим образом:

Код

SomeProc(4, 10, PInteger(Nil)^);


Человеку не нужен был результат, а волновали только действия внутри функции. smile

Кстати, Rrader, подобные методы от тебя пошли насколько помню по нашему форуму  smile 
И к тебе у меня вопрос:

Ты показывал такие примеры на WinAPI функциях. Как там обрабатываются значения типа этого PInteger(Nil)^ ?
Просто идет глушение ошибок или же есть какая-то проверка вроде:

Код

if @Param <> nil then
  { Действия }


???

И мне интересно - как еще можно поизвращаться с чем нибудь в этой простейшей процедуре? smile

Автор: Rrader 12.12.2009, 19:52
THandle, я когда увидел тему, я в шоке легком был. Потому что я зашел в клуб, чтобы создать подобную тему smile Тоже про ошибку в функции. Эта функция, предложенная тобой, может еще в одном случае завалить программу. 
Цитата(THandle @  13.12.2009,  01:17 Найти цитируемый пост)
Кстати, Rrader, подобные методы от тебя пошли насколько помню по нашему форуму smile 

Я лишь напомнил, эта практика давно была известна многим программистам Delphi. Это как с последовательностью Фибоначчи, ее знали египтяне, а называется она по имени средневекового математика smile 
Цитата(THandle @  13.12.2009,  01:17 Найти цитируемый пост)
Как там обрабатываются значения типа этого PInteger(Nil)^ ?

Ну, например, GetWindowThreadProcessId:
Код

DWORD GetWindowThreadProcessId(
    HWND    hwnd,
    LPDWORD lpdwProcessId)
{
    PTHREADINFO ptiWindow;
    DWORD dwThreadId;

    if ((ptiWindow = PtiWindow(hwnd)) == NULL)
        return 0;

    if (ptiWindow == PtiCurrent()) {

        if (lpdwProcessId != NULL)
            *lpdwProcessId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
        ...  

Просто проверка на не NULL (0). Функция получает указатель на входе. А теперь смотрим, что Delphi передает:
Код

...

function MyGetWindowThreadProcessId(hWnd: HWND; var dwProcessId: DWORD): DWORD;
  stdcall; external 'user32.dll' name 'GetWindowThreadProcessId';

...

procedure TForm1.Button1Click(Sender: TObject);
begin
  MyGetWindowThreadProcessId(Handle, PDWORD(nil)^);
end;

Код

push    0
mov     eax, Form1
call    TWinControl.GetHandle
push    eax  
call    MyGetWindowThreadProcessId


Добавлено через 3 минуты и 12 секунд
Цитата(THandle @  13.12.2009,  01:17 Найти цитируемый пост)
И мне интересно - как еще можно поизвращаться с чем нибудь в этой простейшей процедуре? smile 

Что имеется в виду?

Автор: THandle 12.12.2009, 20:44
Цитата(Rrader @  12.12.2009,  19:52 Найти цитируемый пост)
THandle, я когда увидел тему, я в шоке легком был. Потому что я зашел в клуб, чтобы создать подобную тему smile Тоже про ошибку в функции.


А что ты там хотел написать? smile

Цитата(Rrader @  12.12.2009,  19:52 Найти цитируемый пост)
Ну, например, GetWindowThreadProcessId:


Понятно, спасибо smile

Цитата(Rrader @  12.12.2009,  19:52 Найти цитируемый пост)

Что имеется в виду? 


Имеется ввиду как раз вот такие случаи:

Цитата(Rrader @  12.12.2009,  19:52 Найти цитируемый пост)
Эта функция, предложенная тобой, может еще в одном случае завалить программу. 


А так же при каких обстоятельствах они могут возникнуть smile

Автор: REZiaMIX 21.3.2011, 16:03
Я ужасный некрофил, но данный пример используется часто для демонстрации ошибки:
SomeProc(MAX_INT,MAX_INT,...);
выйдет совершенно не тот результат, которого ожидали ;)

Автор: roschinspb 22.3.2011, 18:44
Проверку на пустоту можно сделать так:
Код

procedure SomeProc(const A, B: Integer; var Result: Integer);
begin
  if Addr(Result) <> nil then
    Result := A + B;
end;

procedure TForm4.Button2Click(Sender: TObject);
begin
  SomeProc(4, 10, PInteger(Nil)^);
end;

Если приведение типов использовать бездумно,  можно скольугодно много нагородить такого:
Код

procedure TForm4.Button2Click(Sender: TObject);
var X1, X2: integer;
    I: Pointer;
begin
  X1 := 4;
  X2 := 10;
  I := Sender;
  SomeProc(X1, X2, PInteger(I)^);
end;

А это уже как повезет, может прокатить, а может и нет:
Код

procedure TForm4.Button2Click(Sender: TObject);
var X1, X2: integer;
    I: PInteger;
begin
  X1 := 4;
  X2 := 10;
  SomeProc(X1, X2, I^);
end;
 Видимо товаристч действительно про WIN API начитался, там частенько можно вызывать какую-нибудь функцию дважды, в первый раз с nil, только для получения размера возвращаемых данных, а потом уже выделять память и передавать реальный указатель, но там, правда, специально оговаривается в документации, что так можно.

Автор: CodeMonkey 22.3.2011, 18:57
Цитата(roschinspb @  22.3.2011,  19:44 Найти цитируемый пост)
 Видимо товаристч действительно про WIN API начитался, там частенько можно вызывать какую-нибудь функцию дважды, в первый раз с nil, только для получения размера возвращаемых данных, а потом уже выделять память и передавать реальный указатель, но там, правда, специально оговаривается в документации, что так можно. 


Ну так для таких случаев и прототип ведь другой используется. PInteger называется. А не var Integer.

Правило простое:
- Видим PInteger - вероятно, функция примет nil.
- Видим var Integer/out Integer - функция nil не примет.

Достаточно прозрачная логика. А var с nil - это кривейшая кривость. Всё равно что Self на nil проверять. Как ремни безопасности - пожалуйста. Как штатная логика - пристрелить на месте.

Автор: roschinspb 23.3.2011, 12:11
Цитата(CodeMonkey @ 22.3.2011,  18:57)
- Видим PInteger - вероятно, функция примет nil.
- Видим var Integer/out Integer - функция nil не примет.

Достаточно прозрачная логика. А var с nil - это кривейшая кривость. Всё равно что Self на nil проверять. Как ремни безопасности - пожалуйста. Как штатная логика - пристрелить на месте.

Наверно в книжках "Библия Pascal/Delphi/С/++/# для профессионалов" smile об это не написано.
P.S. формально говоря ошибка то не в процедуре, а вне её.

Автор: Romkin 26.3.2011, 22:35
CodeMonkey, все правильно. var - значит что параметр обязан быть, причем нужного типа.
Ассерты, конечно, есть, но на такое писать никаких проверок не хватит. Ну проверил на nil, и что? Он же получит отлуп и подаст PInteger(Form1)^ например.  smile Проверяйте!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)