На главную Наши проекты:
Журнал   ·   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_
  
> Invalid typecast
    Вот есть некая процедура и один из её параметров это свой тип например:
    ExpandedWrap disabled
      type
        TA1   = packed array[0..15] of byte;


    и я хочу вызвать эту процедуру но уже с использованием другого типа который по сути тот же самый, и получаю ошибку - Invalid typecast
    пример:
    ExpandedWrap disabled
      procedure proc(Value: Ta1);
      begin ........ end;
      ...
      var
        ab: Tbytes;
        aab: array of byte;
      begin
         proc(ab); - Invalid typecast
         proc(aab); - Invalid typecast
      end;

    Понятное дело, что можно свести всё к одному типу, но на этот перебор будет уходить время, переписывать процедуры тоже плохой вариант, поэтому вопрос может как-то можно сделать то что я хочу с минимальной затратой ресурсов ?
    Сообщение отредактировано: Jiro -
      переписать только функцию:
      ExpandedWrap disabled
        procedure proc(const Value; const ASize: DWORD);
        var
          ptr: pbyte;
        begin
          ptr:= @Value;
          // далее - работа через ptr^
        end;
        ExpandedWrap disabled
          type
            PA1 = ^TA1;
            TA1 = packed array[0..15] of byte;
          ...
          begin
            Proc(PA1(@ab[0])^);
            Proc(PA1(@aab[0])^);
          end;
        ?
        Сообщение отредактировано: Filka -
          Параметр - открытый массив (Value: array of Byte) не подойдёт?

          P.S. Пример не соответствует фразе
          >другого типа который по сути тот же самый
            Jiro
            Один из вариантов - использовать в качестве параметра открытый массив Value:array of byte, вместо которого можно будет передавать и статические (типа ТА1), и динамические (типа TBytes) массивы байтов.

            Другой вариант - передавать массив по указателю на первый элемент
            ExpandedWrap disabled
              type
                pA1 = ^TA1;
                TA1   = packed array[0..15] of byte;
               
              procedure proc(Value: pA1);
              ...
              proc(@ab[0]); //при таком вызове ab м.б. и статическим и динамическим
              Всем thx.
              Хотелось именно без модификации процедуры, тк. процедур много и в каждой свой тип и они не мои, а из чужего юнита, который апдейтится не мной.
                а зачем? в процедуру передается строгий тип на 16 байт по ссылке, ты же хочешь впихнуть туда динамический тип. Компилятор в данном случае уже контролировать не сможет. в нутри функции тоже отследить динамический массив не получится (так как функция думает что это статический массив). и это приведет только к одному, к AV.

                но как вариант можно решить проблему за счет хелперов или операторов


                helper
                ExpandedWrap disabled
                  uses
                    System.Math;
                   
                  type
                    TBytesHelper = record helper for TBytes
                    public
                      function toTA1: TA1;
                    end;
                   
                  { TBytesHelperHelper }
                   
                  function TBytesHelper.toTA1: TA1;
                  begin
                    FillChar(Result, sizeof(Result), 0);
                    if Length(Self) > 0 then
                      Move(Self[0], Result, Min(sizeof(Result), Length(Self)));
                  end;
                  //use
                  proc(ab.toTA1);


                operator
                ExpandedWrap disabled
                  type
                    TMyRecord = record
                    private
                      InternalArray: TBytes;
                    public
                      constructor Create(arr: TBytes); overload;
                      constructor Create(Memory: PByte; Size: NativeInt); overload;
                      class operator Implicit(Value: TMyRecord): TA1;
                    end;
                   
                   
                  { TMyRecord }
                   
                  constructor TMyRecord.Create(arr: TBytes);
                  begin
                    InternalArray := arr;
                  end;
                   
                  constructor TMyRecord.Create(Memory: PByte; Size: NativeInt);
                  begin
                    SetLength(InternalArray, size);
                    if Size > 0 then
                      Move(Memory^, InternalArray[0], Size);
                  end;
                   
                  class operator TMyRecord.Implicit(Value: TMyRecord): TA1;
                  begin
                    FillChar(Result, sizeof(Result), 0);
                    if Length(Value.InternalArray) > 0 then
                      Move(Value.InternalArray[0] ,Result, Min(sizeof(Result), Length(Value.InternalArray)));
                  end;
                   
                  //use
                  var
                    Array1: TBytes;
                    rc: TMyRecord;
                  ...
                    Array1 :=  TBytes.Create(1,2,3,4,5,6,7,8,9,0);
                    rc := TMyRecord.Create(Array1);
                    proc(rc);
                  //или попроще
                    proc(TMyRecord.Create(TBytes.Create(1,2,3,4,5,6,7,8,9,0)));
                Сообщение отредактировано: ViktorXP -
                  Цитата ViktorXP @
                  FillChar(Result, sizeof(Result), 0);

                  Хм, с каких пор Result стал получать осмысленное значение до вызова функции?

                  Добавлено
                  Цитата Jiro @
                  и я хочу вызвать эту процедуру но уже с использованием другого типа который по сути тот же самый, и получаю ошибку - Invalid typecast

                  Не тот же самый. Динамический массив и фиксированный массив - два физически очень разных типа.

                  Если не имеешь возможности переделать модуль - да, только пиши конверторы из своего типа в используемый. Либо добавляй обертки типа
                  ExpandedWrap disabled
                    function proc_mytype(A: Tbytes)
                    begin
                      proc(TBytesToTA1(A));
                    end;
                    Цитата Fr0sT @
                    Хм, с каких пор Result стал получать осмысленное значение до вызова функции?

                    С незапамятных - для сложных типов Result передается как дополнительный var-параметр и соотв-но содержит то, что в нем было до вызова функции.
                    PS: Особенно "прикольно\неожиданно" это выглядит в функциях, возвращающих string
                      leo, забавно, спасибо. Хотя это скорее хакофича, и рассчитывать на нее не стоит, к тому же это повергает в когнитивный диссонанс читающего код
                        Цитата Fr0sT @
                        Хотя это скорее хакофича, и рассчитывать на нее не стоит, к тому же это повергает в когнитивный диссонанс читающего код

                        ???? Result является полноценной переменной (параметром) и всегда таким был
                        Не путай с С/С++ в которой до return результата нет.

                        То что ты не использовал эту возможность (хотя я уверен что использовал. просто сам этого не знал или не задумывался об этом) не коем образом не делает ее "хаком".

                        Добавлено
                        пс. в доказательства, что это полноценная переменная, можешь набросать примеры и увидеть что result подчиняется всем законам переменных. да и в стандарте можно по ковыряться паскалевском. я думаю там все это задокументировано
                        Сообщение отредактировано: ViktorXP -
                          ViktorXP
                          Можно простой пример? Я хочу понять о чем речь.
                            ViktorXP, покажи мне реально оправданный пример использования предыдущего значения Result.
                              для начала (что бы я не быть голословным) загляним в Object Pascal Language Guide
                              там есть писание синтаксиса и поведения функции (нам интересны только аспекты поведения result)
                              user posted image
                              Тут сказано что в каждой функции есть неявная локальная переменная result, которая имеет тот же тип что и результат функции. и присвоение ей значение будет тоже самое что и присвоение наименованию функции. также локальную переменную result можно использовать для получения значения результата внутри функции.

                              то есть функцию
                              ExpandedWrap disabled
                                function MyFunc(): Integer;

                              можно рассматривать как
                              ExpandedWrap disabled
                                function MyFunc(): Integer;
                                var
                                  Result: Integer absolute MyFunc;//так она не соберется но для наглядности сойдет


                              если интересно
                              также для наглядности мы можем рассмотреть эту функцию как процедуру с out параметром
                              ExpandedWrap disabled
                                procedure MyFunc(out Result: Integer);
                              поведения параметра result, с точки зрения паскаля, не будет ничем отличатся от поведения result функции. он также будет ругаться на забывчивость проинициализировать ее внутри процедуры и будет подчинятся всем другим "законам" языка.


                              Предположу что тебя смущает ошибка "W1035 Return value of function 'MyFunc' might be undefined" при попытке считать значение из result (или выходя из функции) не проинициализировав ее перед этим.
                              но сама переменная от этого никуда не делась, под ее даже память выделена (изредка конечно нет, но в данной ситуации мы это не рассматриваем)
                              в довесок сообщу что ты также получишь ошибку если попытаешься работать с не проинициализированой локальной переменной
                              ExpandedWrap disabled
                                function MyFunc(): Integer;
                                var
                                  I: Integer;
                                begin
                                  if Result = 1 then // W1035 Return value of function 'MyFunc' might be undefined
                                    Exit(10);
                                  if I = 1 then // W1036 Variable 'I' might not have been initialized
                                    Exit(1);
                                end;

                              Это связано с тем что сам "компилятор" не чистит стек для локальных переменных и результата. и там может находится все что угодно (мусор от предыдущих функций/процедур)
                              это не касается массивов/строк/интерфейсов, "компилятор" их проинициализирует (это оговорено в том же Guide. будет желание можешь поискать)
                              ExpandedWrap disabled
                                function MyFunc(): string;
                                begin
                                  if Result = '' then // никакой ошибки не будет
                                    Exit('empty');
                                end;


                              В чем же есть оправдания использовать result сразу, без использования дополнительной переменной?
                              а переодически вижу код
                              ExpandedWrap disabled
                                function MyFunc(): Integer;
                                var
                                  Ret: Integer;
                                begin
                                  Ret := 0;
                                  ...
                                  Result := ret;
                                end;
                              Подобный код появляется в двух случаях: человек раньше писал на с/с++ и он привык что результат нужно присваивать в конце; человек не знает о поведения result в паскале.
                              и в первом, и во втором случае это говно-код.
                              Бессмысленно заводить переменную если она у тебя уже есть. Если на простом типе integer ты теряешь всего 4 байта (x32). то в случае структуры в 16 байт ты в стек положешь лишние 16 байт. При этом еще и потеряешь на копировании при выходе из функции (ведь нужно скопировать твои данные из локальной переменной в result).
                              ExpandedWrap disabled
                                type
                                  TMyChars = array[0..9] of char;
                                 
                                function MyFunc(): TMyChars;
                                var
                                  LocalParam: TMyChars;
                                begin
                                  LocalParam := '0123456789';
                                  Result := LocalParam;
                                end;

                              user posted image

                              пс. я надеюсь что свою мысль я донес максимально доступно.
                              пс.Imge извиняюсь если картинки получились через чур большими, у меня разрешение дисплея большое. (картинки выглядят маленькими)
                              Сообщение отредактировано: ViktorXP -
                                ViktorXP, спасибо и уважуха за развернутый ответ, но ты меня не понял. По большей части это все азбука и мне, разумеется, известно. Возражения у меня вызвала вот эта конструкция
                                ExpandedWrap disabled
                                  function TBytesHelper.toTA1: TA1;
                                  begin
                                    FillChar(Result, sizeof(Result), 0);
                                    if Length(Self) > 0 then
                                      Move(Self[0], Result, Min(sizeof(Result), Length(Self)));
                                  end;

                                т.к. в переопределенные типы я не вникал, то решил, что Result - это динамический массив, длину которого ты с какого-то перепугу используешь. Сейчас посмотрел - TA1 - статический массив, для него все верно. Т.ч. вопрос исчерпан.

                                Хотя вот leo понял причину моего недоумения :)
                                  Цитата ViktorXP @
                                  Тут сказано что в каждой функции есть неявная локальная переменная result
                                  ... также получишь ошибку если попытаешься работать с не проинициализированой локальной переменной
                                  Это связано с тем что сам "компилятор" не чистит стек для локальных переменных и результата.
                                  ... это не касается массивов/строк/интерфейсов, "компилятор" их проинициализирует

                                  Не совсем так. Если заглянуть "под капот" Program Control -> Handling Function Results, то увидим, что результат функции "сложного" типа (к коим относятся статические массивы, записи и множества размером более 4 байт, а также managed типы строки\дин.массивы\варианты) передаются в функцию как дополнительный var-параметр. Поэтому в случае с возвратом строки компилятор не ругается на проверку Result не потому, что "локальная переменная" Result:string автоматически инициализируется нулем внутри функции, а потому, что в данном случае Result - это var-параметр, обязанность инициализации которого лежит на вызывающей стороне. Точно также компилятор не будет ругаться и в случае не managed-типа результата - записи, стат.массива или множества.
                                  Например:
                                  ExpandedWrap disabled
                                    function Foo1:string; //по сути это procedure _Foo1(var Result:string);
                                    begin
                                       if Result = '' then
                                         Result:='empty string';
                                       ShowMessage(Result);  
                                    end;
                                    function Foo2:TPoint; //по сути это procedure _Foo2(var Result:TPoint);
                                    begin
                                       inc(Result.X);
                                       inc(Result.Y);
                                       ShowMessage(Format('%d; %d',[Result.X,Result.Y]));
                                    end;
                                    var
                                       s:string;
                                       P:TPoint;
                                    begin
                                       s:='Hello,World';  //
                                       s:=Foo1;           //= _Foo1(s);
                                       P.X:=10; P.Y:=10;
                                       P:=Foo2;           //= _Foo2(P);
                                    end;

                                  поскольку тут Foo1 и Foo2 по сути являются процедурами с var-параметрами, то компилятор НЕ ругается не только на отсутствие инициализации Result внутри этих функций, но также и на якобы неиспользуемые присваивания значений переменных s и P в вызывающей функции.

                                  Добавлено
                                  PS: Поэтому в общем случае, Result это не такая уж "обычная локальная переменная", как следует из ее "высокоуровневого" описания. В частности, присваивание Result "сразу, без использования дополнительной переменной" может приводить к различному поведению\результату в случае необработанного исключения в функции - для типов Result, возвращаемых через регистры, значение переменной, которой присваивается значение функции, в случае ошибки не изменится, а для типов, передаваемых через var-параметр оно меняется "сразу" и соотв-но будет содержать значение Result на момент возникновения исключения.
                                    Это уже особенности реализации компилятора. Которые не опровергают существования result как локальной переменной, но накладывает небольшие условия.

                                    пс. но странно будет сотрется код в котором при исключении я не буду корректировать возвращаемый результат или иными способами обрабатывать это исключение.
                                    1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                    0 пользователей:


                                    Рейтинг@Mail.ru
                                    [ Script execution time: 0,0527 ]   [ 15 queries used ]   [ Generated: 29.07.25, 20:52 GMT ]