На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Причуды Delphi-ского компилятора
    Есть задача: найти в списке элемент, удовлетворяющий заданному условию (предикату). Представим себе, что у нас уже есть структура данных «список» и функция поиска, принимающая предикат, который также является функцией, возвращающей значений булевского типа.
    Наваял такой код:
    ExpandedWrap disabled
      ...
      var
        Form1: TForm1;
       
      type
        TIntList = array of integer;
        TPredicate = function(x: Integer): Boolean;
       
      implementation
       
      {$R *.dfm}
       
      function Find(list: TIntList; f: TPredicate): Integer;
      var
        b: boolean;
        i: integer;
      begin
       
        for i := 0 to high(list) do
        begin
          b := f(list[i]);
          if b then
          begin
            Result := list[i];
            Exit;
          end;
        end;
       
        Result := 0;
      end;
       
      procedure Test;
      var
        t: TIntList;
        n: Integer;
        v: integer;
        procedure InitT;
        begin
          setLength(t, 2);
          t[0] := 3;
          t[1] := 6;
         end;
        function GreaterN(x: Integer): Boolean;
        begin
          if x >= n then
            result := true
          else
            result := false;
        end;
      begin
        n := 5;
        initT;
        ShowMessage(IntToStr(Find(t, @GreaterN)));
      end;
       
      procedure TForm1.Button1Click(Sender: TObject);
      begin
        test;
      end;

    Прикол в том, что ф-ция GreaterN, вызов которой происходит из Find, всегда возвращает false, хотя второй элемент списка (t[1] := 6) передаваемый в качестве параметра > n (где n = 5).
    И как это объяснить?
    Сообщение отредактировано: DelphiLexx -
      о_О и вправду делфи "чудит" :) с определением переменной n явно проблемы .. если вынести её глобально ок
      не знаю как можно разрулить..мб написать маленький клас?
      Сообщение отредактировано: qwertyman -
        ExpandedWrap disabled
          ShowMessage(IntToStr(Find(t, @GreaterN)));

        убери @ и читай справку по появившейся ошибке
          О_о
          А с чего вы взяли, что ваш код должен работать?

          Вы взяли адрес локальной процедуры и передали его в Find. Окей, согласно справке:

          Цитата
          If you take any procedure or function heading and remove the identifier after the word procedure or function, what's left is the name of a procedural type. You can use such type names directly in variable declarations (as in the previous example) or to declare new types:

          type
          TIntegerFunction = function: Integer;

          procedure FuncProc(P: TIntegerFunction); { FuncProc is a procedure whose only parameter is a parameterless integer-valued function }

          On Win32, the variables shown in the previous example are all procedure pointers - that is, pointers to the address of a procedure or function.


          Внимание, вопрос: если в Find передаётся указатель на код, то как этот код получит доступ к локальной переменной внутри другой функции? Локальные переменные имеют смысл только внутри своей процедуры, но не для внешних процедур. Беря указатель на функцию, вы делаете её внешней по отношению к Test. Следовательно, как у внешней процедуры, у неё нет доступа к локальным переменным процедуры Test. Да, код GreaterN компилируется, т.к. он корректен. Да, указатель на функцию компилятор разрешает брать для любой функции. Но при этом используется тот же самый код. Т.е. при @GreaterN не создаётся новой функции - используется уже готовый код. Получается, что GreaterN в качестве локальной процедуры работает с n. GreaterN в качестве внешней процедуры обращается куда-то. Когда в GreaterN вы обращаетесь к n, вы на самом деле используете относительную ссылку, т.е. говорите: прочитать второй параметр у вышестоящей процедуры. Когда GreaterN вызывается из Find на этом месте находятся какие-то другие данные.
          Вам, на самом деле, нужно передавать не только код, но и данные, с которыми он будет работать.
          Если читать справку дальше:

          Цитата
          If you want to reference a method of an instance object (see Classes and objects), you need to add the words of object to the procedural type name. For example

          type
          TMethod = procedure of object;
          TNotifyEvent = procedure(Sender: TObject) of object;

          These types represent method pointers. A method pointer is really a pair of pointers; the first stores the address of a method, and the second stores a reference to the object the method belongs to.


          Таким, образом, у вас есть несколько вариантов правильного действия:

          1. Использовать глобальные переменные.
          2. Передавать вместе с процедурой указатель на данные, с которыми процедура будет работать.
          3. Вместо процедур использовать методы.
          4. Использовать анонимные процедуры. Они позволяют автоматически "копировать к себе" нужные переменные из стека.

          Функционально все эти подходы равны. Отличается лишь внешний вид, а суть одна: передаётся код и данные.
          Сообщение отредактировано: CodeMonkey -
            Цитата CodeMonkey @
            Получается, что GreaterN в качестве локальной процедуры работает с n. GreaterN в качестве внешней процедуры обращается куда-то.

            НО если посмотреть в отладчике и побегать по F7, то увидим n определяется правильно = 5.
            Цитата CodeMonkey @

            Использовать анонимные процедуры. Они позволяют автоматически "копировать к себе" нужные переменные из стека.

            Собственно из-за них то я и затеял тему смотрим здесь http://forum.vingrad.ru/topic-96077.html

            Да.. глюки то одназначно будут т.к. когда я делаю так @GreaterN, то GreaterN по отношению к Test становиться в Find внешней ф-цией, а значит и доступа к локальным переменным т.е. в данном случак к n будет неправильным.

            Но это все фигня, меня удивляет почему компилятор не ругается на очевидные ошибки?
              Цитата DelphiLexx @
              Но это все фигня, меня удивляет почему компилятор не ругается на очевидные ошибки?

              а тебя не смущает, что компилер не ругается например на такой код: PInteger(@StrVar)^ := 10; ???

              ты сам забил на компилер, когда стал пользоваться нетипизированными указателями.
              Написал бы так
              ShowMessage(IntToStr(Find(t, GreaterN)));

              компилер бы те четко сказал, что так нельзя и отказался бы такой код компилить.

              ЗЫ Прежде чем ругать компиляторы - не мешало бы язык выучить.
                Цитата DelphiLexx @
                Но это все фигня, меня удивляет почему компилятор не ругается на очевидные ошибки?

                Он ругается :)

                Передача процедуры в другую процедуру - это просто указание её имени, как вам уже два раза здесь ткнули. Вы же берёте указатель в чистом виде. Разумеется, компилятор на такое ругаться не станет.

                P.S. На самом деле, если бы вы включили строгую проверку типов (Typed @ Operator), то компилятор не дал бы вам и этого сделать (типа, указатель - не то же самое, что процедурный тип).
                Сообщение отредактировано: CodeMonkey -
                  Цитата jack128 @
                  Прежде чем ругать компиляторы - не мешало бы язык выучить.

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

                  Добавлено
                  Цитата CodeMonkey @
                  Передача процедуры в другую процедуру - это просто указание её имени, как вам уже два раза здесь ткнули. Вы же берёте указатель в чистом виде. Разумеется, компилятор на такое ругаться не станет.

                  P.S. На самом деле, если бы вы включили строгую проверку типов (Typed @ Operator), то компилятор не дал бы вам и этого сделать (типа, указатель - не то же самое, что процедурный тип).

                  Согласен
                    Цитата DelphiLexx @
                    и язык знаю не хуже тебя. успокойся
                    :lool: :D
                      Цитата Romkin @

                      что смешного
                        смешно, когда человек, который утверждает, что знает язык, задаёт такие вопросы как #1
                          Цитата jack128 @
                          смешно, когда человек, который утверждает, что знает язык, задаёт такие вопросы как #1

                          Читай #5 без последнего предложения
                          Сообщение отредактировано: DelphiLexx -
                            То что ты питаешся зделать, собсно что почерпнул из этой статьи
                            Цитата DelphiLexx @
                            Собственно из-за них то я и затеял тему смотрим здесь http://forum.vingrad.ru/topic-96077.html
                            называется (цытирую из твоей сатьи)
                            Цитата
                            В контексте языков программирования под лямбда-функцией понимают анонимную функцию. Т.е. функцию, которой не сопоставлено никакое имя, просто значение функционального типа. Например:

                            теперь переходим на описаний новшеств языке в 2009 делфи http://8vmr.livejournal.com/6114.html
                            Цитата
                            2. Анонимные методы (лямбды), с ними же и замыкания (closures):
                            Я думаю дальше объяснять ничего не нужно
                            Сообщение отредактировано: ViktorXP -
                              Цитата ViktorXP @
                              теперь переходим на описаний новшеств языке в 2009 делфи http://8vmr.livejournal.com/6114.html
                              Цитата
                              2. Анонимные методы (лямбды), с ними же и замыкания (closures):
                              Я думаю дальше объяснять ничего не нужно

                              Эту статью я уже виделю Наконец-то, мы плавненько перешли к новшествам BDS2009 - ананимным методам и замыканиям. Кто-нибудь может превести пример с использованием этих технологий для решения поставленной задачи.
                                Цитата DelphiLexx @
                                TPredicate = reference to function(x: Integer): Boolean;

                                и все будет работать.
                                  Цитата jack128 @

                                  и все будет работать.

                                  Не мог бы примерчиком показать, а то не совсем понятно
                                    Цитата DelphiLexx @
                                    Не мог бы примерчиком показать, а то не совсем понятно

                                    ExpandedWrap disabled
                                      type
                                        TIntList = array of integer;
                                        TPredicate = reference to function(x: Integer): boolean;
                                       
                                      implementation
                                       
                                      {$R *.dfm}
                                       
                                      function Find(list: TIntList; f: TPredicate): Integer;
                                      var
                                        b: boolean;
                                        i: integer;
                                      begin
                                       
                                        for i := 0 to high(list) do
                                        begin
                                          b := f(list[i]);
                                          if b then
                                          begin
                                            Result := list[i];
                                            Exit;
                                          end;
                                        end;
                                       
                                        Result := 0;
                                      end;
                                       
                                      procedure Test;
                                      var
                                        t: TIntList;
                                        n: Integer;
                                        v: integer;
                                        GreaterN:TPredicate;
                                        procedure InitT;
                                        begin
                                          setLength(t, 2);
                                          t[0] := 3;
                                          t[1] := 6;
                                         end;
                                      begin
                                        n := 5;
                                        initT;
                                        GreaterN := function(x: Integer): Boolean
                                        begin
                                          result := ( x >= n);
                                        end;
                                       
                                        ShowMessage(IntToStr(Find(t, GreaterN)));
                                      end;
                                    или можно сразу в find вбить функцию без использования переменной

                                    Добавлено
                                    если у тебя 2009 то уже и про такие вещи можеш забыть
                                    Цитата DelphiLexx @
                                    Result := list[i];
                                    Exit;
                                    теперь тут можно спокойно написать
                                    ExpandedWrap disabled
                                      Exit(list[i]);
                                      Цитата ViktorXP @
                                      или можно сразу в find вбить функцию без использования переменной

                                      Спасибо, теперь понятно.
                                      Цитата ViktorXP @
                                      теперь тут можно спокойно написать
                                      Exit(list[i]);

                                      ага это я знал.

                                      А когда обещают Borladn или CodeGear или Embarcadero (просто не знаю как нызываь их) оффициальный выход BDS2009?
                                      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                      0 пользователей:


                                      Рейтинг@Mail.ru
                                      [ Script execution time: 0,0509 ]   [ 16 queries used ]   [ Generated: 26.04.24, 09:01 GMT ]