Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с нетипизированными указателями (Pointer)??  (Прочитано 21420 раз)
0 Пользователей и 1 Гость смотрят эту тему.
newmen_
Гость
« : 21-03-2006 12:10 » 

Уважаемые профи, помогите, пожалуйста!

Мне необходимо передать массив n-ой длины в функцию, и соотв. вернуть массив возможно другой длины.
Кто знает какие способы, поделитесь, пожалуйста!!!

Я в качеств предполагал использовать динамические массивы. Но как прочитал в хелпе, функцией SetLength можно задавать лишь массив длиной от 0 - 255, что не удовлетворяет. Хотя я пробовал выводить в memo:
Код:
type
  tArrayOfByte=array of byte;
var
  arrb:^tArrayOfByte;
begin
  new(arrb);
  setlength(arrb^,999999);
  memo1.lines.add(strtoint(length(arrb^)));
  dispose(arrb); arrb:=nil;
Вроде бы все нормально проходило. Чему же верить?

Теперь остановился н с типом Pointer.
Код:
procedure TForm1.Button4Click(Sender: TObject);
{O-}
var
  bb:pointer;
  arrb:^tArrayOfByte;
  bbsz,i:dword;
  hmem:cardinal;
  tmp:byte;
begin
  bbsz:=128;
//=========Случайные данные для эксперимента============== 
  new(arrb);
  setlength(arrb^,bbsz);
  for i:=0 to bbsz-1 do begin
    arrb^[i]:=random(255);
  end;
//===============================================
  hmem:=GlobalAlloc(GMEM_FIXED,bbsz);
  bb:=GlobalLock(hmem);

    CopyMemory(bb,arrb,bbsz);
    NormalizeData8(bb,bbsz,128);

    GlobalUnlock(GlobalHandle(bb));
    GlobalFree(GlobalHandle(bb));
    //dispose(arrb);
    arrb:=nil;

end;

Процедура NormalizeData8 и 2 вспомогательные:
Код:
//перед вызовом, buff необходимо резервировать с пом. f GlobalAlloc, GlobalLock и освобождать соотв.
//NPoints- количество временных отметок для нормализации
function NormalizeData8(var buff:pointer; var buffsz:dword; NPoints:dword):integer;
var
  RPoints,i,ind1,ind2,tmp: dword;
  Knrr,ind: real;
  buff2: pointer;
  hmem: cardinal;
  arrb: ^tArrayOfByte;

begin
  result:=0;
  if GlobalSize(GlobalHandle(buff))<buffsz then begin
    ShowMessage('Ошибка: При вызове f NormalizeData8: неправильно инициализирован параметр buff');
    result:=-1; exit;
  end;

  hmem:=GlobalAlloc(GMEM_FIXED,NPoints);
  buff2:=GlobalLock(hmem);
  for i:=0 to NPoints-1 do begin
      SetByteToPtr(buff2,i,GetByteFromPtr(buff,i)); //для простоты, на самом деле происходит некое преобразование
  end;
  buffsz:=NPoints;
  if GlobalUnlock(GlobalHandle(buff)) then GlobalFree(GlobalHandle(buff));
  buff:=buff2; buff2:=nil;
end;

function GetByteFromPtr(p:pointer; ind:dword):byte;
var
  pp:cardinal;
begin
  if GlobalSize(GlobalHandle(p))<=ind then begin
    ShowMessage('Ошибка: При вызове f GetByteFromPtr: индекс ('+inttostr(ind)+
                ') превышает размер выделенной памяти ('+inttostr(GlobalSize(GlobalHandle(p)))+')');
    exit;
  end;
  asm
    pusha

    mov esi,dword ptr ind
    mov edx,[p]
    mov al,byte ptr [edx+esi]
    mov byte ptr result,al

    popa
  end;
end;

function SetByteToPtr(p:pointer; ind:dword; val:byte):byte;
begin
  if GlobalSize(GlobalHandle(p))<=ind then begin
    ShowMessage('Ошибка: При вызове f SetByteToPtr: индекс ('+inttostr(ind)+
                ') превышает размер выделенной памяти ('+inttostr(GlobalSize(GlobalHandle(p)))+')');
    exit;
  end;
  asm
    pusha

    mov esi,dword ptr ind
    mov edx,[p]
    mov al,byte ptr val
    mov byte ptr [edx+esi],al

    popa
  end;
end;

В ассемблерных ф-ях из массива (т.е. указателя) берутся совсем не те числа, которые были туда скопированы. Подскажите, возможно я неправильно адресую память?
Или может есть другие способы работы с нетипизированными указателями для пересылки в подпрограммы динамических массивов данных.

Уже и не знаю, что придумать...
« Последнее редактирование: 04-12-2007 21:26 от Алексей1153++ » Записан
PooH
Глобальный модератор

ru
Offline Offline
Пол: Мужской
... и можно без хлеба!


« Ответ #1 : 21-03-2006 13:47 » 

1. Где написано, что в SetLength можно задавать лишь массив длиной от 0 - 255 (по-моему, это только для строк такое ограничение)
2. А в TForm1.Button4Click в bb нормально данные копируются?
Записан

Удачного всем кодинга! -=x[PooH]x=-
newmen_
Гость
« Ответ #2 : 21-03-2006 14:27 » 

1)Спасибо огромное!!! Я бы так и не обратил внимания. Действительно, это ограничение на длину короткой строки. Аж неловко как-то...
Значит есть пути для отступа.

2) Но все-таки полезно разобраться с указателями, как они в делфи работают.
в bb копируется все отлично. Я пробовал в процедуре NormalizeData8 создать второй массив и скопировать в него - CopyMemory(NewMass,buff,buffsz). Значения были верными.

При отладке обнаружил, что в ф-и GetByteFromPtr значения берутся неверные. Возможно pointer указывает на еще один дескриптор или таблицу дескрипторов? ведь ф-я CopyMemory верно все копирует, а напрямую никак. Здесь была моя ладья...
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 22-03-2006 02:48 » 

ИМХО вполне можно обойтись и без asm
Код:
function GetByteFromPtr(p:pointer; ind:dword):byte;
begin
 result:=PByteArray(p)[ind];
end;

function SetByteToPtr(p:pointer; ind:dword; val:byte):byte;
begin
  PByteArray(p)[ind]:=val;
end;
Просто и красиво Улыбаюсь
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
newmen_
Гость
« Ответ #4 : 22-03-2006 03:20 » 

Согласен, но если массив будет больше 32767 байт, то это не годится. Дело в том, что у меня будет обрабатываться звук, а он может занимать, к примеру, 500 кБ.  :Улыбаюсь
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 22-03-2006 03:35 » 

Согласен, но если массив будет больше 32767 байт, то это не годится.
Почему?
Сделал вот такую проверку:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var p:Pointer; hmem,cnt,i: cardinal; val:byte;
begin cnt:=100000;
 hmem:=GlobalAlloc(GMEM_FIXED,cnt);
 p:=GlobalLock(hmem); val:=0;
 for i:=0 to cnt-1 do
 begin
  SetByteToPtr(p,i,val);
  if val=255 then val:=0 else inc(val);
 end;
 for i:=cnt-200 to cnt-1 do
  Memo1.Lines.Add(IntToStr(GetByteFromPtr(p,i)));

 if GlobalUnlock(GlobalHandle(p)) then GlobalFree(GlobalHandle(p));
end;
Все правельно выводится.
« Последнее редактирование: 22-03-2006 03:41 от RomCom » Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
newmen_
Гость
« Ответ #6 : 22-03-2006 05:29 » 

Действительно, но почему?
Ведь в модуле SysUtils:
{ General arrays }
  PByteArray = ^TByteArray;
  TByteArray = array[0..32767] of Byte;

Выходит, при таком преобразовании типов компилятор Делфи сам разрешает выход за пределы массива (назначенного в типе TByteArray), ведь мы указываем на начало нашего исходного массива? Прошу прощения за назойливость, но хочется понять принцип, без этого нельзя писать программы, а в голове это пока не укладывается. Вроде в паскале типы жестко контролируются.
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 22-03-2006 06:06 » 

Нда-с. Сам удивлен.
тогда другой вариант:
Код:
function GetByteFromPtr(p:pointer; ind:dword):byte;
begin
 result:=Byte(pointer((dword(p)+ind))^);
end;

function SetByteToPtr(p:pointer; ind:dword; val:byte):byte;
begin
 Byte(pointer((dword(p)+ind))^):=val;
end;
Здесь напрямую идет преобразование адреса pointer((dword(p)+ind)) т.е. pointer (адрес) преобразуется в число, к ниму прибавляется значение сдвига и полученое значение (адрес в виде числа) преобразуется обратно в pointer. Так что никаких подводных камней быть не должно.
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
newmen_
Гость
« Ответ #8 : 22-03-2006 06:33 » 

Спасибо большущее!!!
Очень хитроумная манипуляция Да-да

Кстати, выявил ошибку. CopyMemory копирует-то отлично (из дин. массива - в выд. область), только вот структура хранения данных там видимо отличается. Поскольку при обратном копировании (из выд. области - в дин. массив) все прекрасно, а при прямом обращении нет.
Стоило убрать эту ф-цию и прямое обращение работает.

Поэтому теперь возник вопро
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 22-03-2006 07:18 » 

Способ копирования не побайтно вряд ли существует. В любом случае данные перебираются и одной ячейки памяти присваивается значение другой. Другое дело уровень реализации и скорость.
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
newmen_
Гость
« Ответ #10 : 22-03-2006 07:19 » 

нашел решение, процедура move учитывает наши особенности (т.е. структуры), может кому пригодится:

var
  ...
  bb:pointer;

begin
...
  move(arrb^[0],bb^,bbsz);
...
end;


ОГРОМНОЕ СПАСИБО ЕЩЕ РАЗ, ДРУЗЬЯ!!!
« Последнее редактирование: 22-03-2006 07:28 от newmen_ » Записан
newmen_
Гость
« Ответ #11 : 22-03-2006 11:44 » 

Способ копирования не побайтно вряд ли существует. В любом случае данные перебираются и одной ячейки памяти присваивается значение другой. Другое дело уровень реализации и скорость.

Это точно.
Просто специально разработанные функции должны быть быстрее, ведь разработчики их оптимизируют как-то Скромно так...
Записан
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #12 : 22-03-2006 13:14 » 

дело не в процедуре move, а в том, как хранятся переменные в менеджере памяти.

Цитата
Dynamic array memory layout 
Offset   Contents
-8   32-bit reference-count
-4   32-bit length indicator (number of elements)
0..Length * (size of element) - 1   array elements

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

RTFM, господа Ага
Записан

x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #13 : 22-03-2006 13:53 » 

Гром! Владыко! Ага я вспомнил! хде моя статья по работе с менеджером памяти дельфей? я её набирал год назад в самолёте летя в Самару. самолёт, в принципе, долетел, но статьи у меня не осталось, ноут был служебный Жаль
Записан

newmen_
Гость
« Ответ #14 : 23-03-2006 04:08 » 

так вопрос и стоял в структуре размещения дин. массива. Спасибо! Теперь хоть часть проблемы понятна. Значит, можно было сделать и так:
CopyMemory(bb,pointer(arrb^),bbsz);

RTFM, господа Ага
жаль,что на русском нет документации Краснею
уж простите за глупые вопросы.. Улыбаюсь
« Последнее редактирование: 23-03-2006 08:24 от newmen_ » Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #15 : 23-03-2006 04:16 » 

arrb:pointer;
CopyMemory(@bb[0],arrb,bbsz);
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
newmen_
Гость
« Ответ #16 : 23-03-2006 08:23 » 

arrb:pointer;
CopyMemory(@bb[0],arrb,bbsz);

Если честно, я не понял. А что за переменная bb? С ума сойти...
« Последнее редактирование: 23-03-2006 08:26 от newmen_ » Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #17 : 23-03-2006 08:28 » 

bb:array of Byte;
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
newmen_
Гость
« Ответ #18 : 23-03-2006 09:02 » 

а, ясно Улыбаюсь
только небольшая описка @bb^[0]
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines