Модераторы: THandle, bems
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Какие ошибки могут быть в коде? 
:(
    Опции темы
THandle
Дата 11.12.2009, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Хранитель Клуба
Group Icon
Награды: 1



Профиль
Группа: Админ
Сообщений: 3639
Регистрация: 31.7.2007
Где: Moscow, Dubai

Репутация: 7
Всего: 372



Всем привет.

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

Код

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


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

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

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

PM   Вверх
Rrader
  Дата 12.12.2009, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: нет
Всего: 191



Вот так можно smile 
Код

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



--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Akella
Дата 12.12.2009, 19:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 7
Всего: 329



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

А по другому и нельзя. Вопрос в том, какие могут быть ошибки?
PM MAIL   Вверх
THandle
Дата 12.12.2009, 19:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Хранитель Клуба
Group Icon
Награды: 1



Профиль
Группа: Админ
Сообщений: 3639
Регистрация: 31.7.2007
Где: Moscow, Dubai

Репутация: 7
Всего: 372



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

Код

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


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

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

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

Код

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


???

И мне интересно - как еще можно поизвращаться с чем нибудь в этой простейшей процедуре? smile
PM   Вверх
Rrader
  Дата 12.12.2009, 19:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: нет
Всего: 191



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 

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


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
THandle
Дата 12.12.2009, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Хранитель Клуба
Group Icon
Награды: 1



Профиль
Группа: Админ
Сообщений: 3639
Регистрация: 31.7.2007
Где: Moscow, Dubai

Репутация: 7
Всего: 372



Цитата(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
PM   Вверх
REZiaMIX
Дата 21.3.2011, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 346
Регистрация: 3.11.2007

Репутация: нет
Всего: 4



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


--------------------
user posted image
PM MAIL   Вверх
roschinspb
  Дата 22.3.2011, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 27.1.2010
Где: С-Пб

Репутация: нет
Всего: нет



Проверку на пустоту можно сделать так:
Код

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, только для получения размера возвращаемых данных, а потом уже выделять память и передавать реальный указатель, но там, правда, специально оговаривается в документации, что так можно.
PM MAIL WWW   Вверх
CodeMonkey
Дата 22.3.2011, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 4
Всего: 89



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


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

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

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


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
roschinspb
  Дата 23.3.2011, 12:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 27.1.2010
Где: С-Пб

Репутация: нет
Всего: нет



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

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

Наверно в книжках "Библия Pascal/Delphi/С/++/# для профессионалов" smile об это не написано.
P.S. формально говоря ошибка то не в процедуре, а вне её.
PM MAIL WWW   Вверх
Romkin
Дата 26.3.2011, 22:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 189
Регистрация: 14.11.2006
Где: Москва

Репутация: нет
Всего: 5



CodeMonkey, все правильно. var - значит что параметр обязан быть, причем нужного типа.
Ассерты, конечно, есть, но на такое писать никаких проверок не хватит. Ну проверил на nil, и что? Он же получит отлуп и подаст PInteger(Form1)^ например.  smile Проверяйте!
PM ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi"
THandle

Добро пожаловать в форум группы "Delphi".

В разделе разрешается:

  • Флудить (в приемлемых величинах)
  • Обсуждать модерирование данного раздела (но не его модератора)
  • Добавлять свои правила если они не противоречат существующим
  • Делать наезды на пешеходов***

Строго запрещено:

  • Размещать рекламу
  • Совершать оскорбления личностей
  • Материться
  • *** Пешеходами не являются (ко)модераторы, админы, участники клуба.

Если Вам понравилась атмосфера форума, заходите к нам чаще! Люблю, целую, вечно Ваш, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Форум группы: delphi | Следующая тема »


 




[ Время генерации скрипта: 0.0826 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.