Страница 3 из 3
Re: cdecl - как это работает и для чего это?
Добавлено: 24.03.2013 22:28:58
bormant
vitaly_l писал(а):Move(s[1], Data^, Size - 1); <== вот здесь непонятно почему s[1]??? А просто s почему нельзя? Зачем [1]???
(PChar(Data) + Size - 1)^ := #0; <== вот этот код, не понимаю, что делает?
Паскалевская короткая строка в s[0] хранит актуальную длину (ту, что возвращает Length[s]), данные начинаются с 1-го элемента -- s[1]. Для длинных строк, AnsiString, данные тоже начинаются в s[1].
-- PChar(Data) -- преобразование Data типа pointer к типу PChar,
-- PChar(Data) + Size - 1 -- вычисление указателя на последний символ выделенного блока,
-- (PChar(Data) + Size - 1)^ -- тот самый последний символ выделенного блока ...
-- (PChar(Data) + Size - 1)^ := #0 -- ... которому присваивается #0, чтобы сформировать ASCIIZ строку.
Кстати, вот немного расширенный пример для иллюстрации:
Код: Выделить всё
{$H+}// это нам дано
const
EOL = #13#10;
type
PChunkRec = ^TChunkRec;
TChunkRec = record
Size: integer;
Data: pointer;
end;
TReadCallback = procedure(Chunk: TChunkRec; Data: Pointer); cdecl;
procedure LoadFromFile(var F: text; ReadCallback: TReadCallback; UserData: Pointer);
var
Chunk: TChunkRec;
s, l: string;
i, n: integer;
begin
while not SeekEof(F) do with Chunk do begin
ReadLn(F, n);
s := '';
for i := n downto 1 do begin
ReadLn(F, l); s := s + l + EOL;
end;
Size := Length(s) + 1;
GetMem(Data, Size);
Move(s[1], Data^, Size - 1);
(PChar(Data) + Size - 1)^ := #0;
if ReadCallback <> nil then ReadCallback(Chunk, UserData);
FreeMem(Data);
end;
end;
// это дописываем мы для работы LoadFromFile
procedure MyHandler(Chunk: TChunkRec; UserData: Pointer); cdecl;
begin
with Chunk do WriteLn(Size, EOL, PChar(Data));
end;
procedure HexDump(Chunk: TChunkRec; UserData: Pointer); cdecl;
const
HD: array [0..15] of char = '0123456789ABCDEF';
var
p: PChar;
begin
with Chunk do begin
WriteLn(Size);
p := Data;
if p<> nil then
while p^ <> #0 do begin
Write(HD[Byte(p^) shr 4], HD[Byte(p^) and $F], ' ');
Inc(p);
if (p-Data) and $F = 0 then WriteLn;
end;
if (p-Data) and $F <> 0 then WriteLn;
WriteLn;
end;
end;
var
f: text;
begin
Assign(f, 'tst.txt'); Reset(f);
LoadFromFile(f, @MyHandler, nil);
Close(f);
Assign(f, 'tst.txt'); Reset(f);
LoadFromFile(f, @HexDump, nil);
Close(f);
end.
Прогон:
Код: Выделить всё
29
Это фрагмент 1 из 1 строки
29
Это фрагмент 2
из 2 строк
30
Это фрагмент 3
из 3
строк
29
Это фрагмент 4 из 1 строки
29
9D E2 AE 20 E4 E0 A0 A3 AC A5 AD E2 20 31 20 A8
A7 20 31 20 E1 E2 E0 AE AA A8 0D 0A
29
9D E2 AE 20 E4 E0 A0 A3 AC A5 AD E2 20 32 0D 0A
A8 A7 20 32 20 E1 E2 E0 AE AA 0D 0A
30
9D E2 AE 20 E4 E0 A0 A3 AC A5 AD E2 20 33 0D 0A
A8 A7 20 33 0D 0A E1 E2 E0 AE AA 0D 0A
29
9D E2 AE 20 E4 E0 A0 A3 AC A5 AD E2 20 34 20 A8
A7 20 31 20 E1 E2 E0 AE AA A8 0D 0A
Re: cdecl - как это работает и для чего это?
Добавлено: 24.03.2013 23:15:50
vitaly_l
Спасибо большое.
Так ещё более понятно.
И наверно последний вопрос:
заменив: (PChar(Data) + Size - 1)^ := #0 вот на такую строку: (12345)^ := #0; будет присваивается #0, чтобы сформировать ASCIIZ строку?
.
Re: cdecl - как это работает и для чего это?
Добавлено: 24.03.2013 23:25:30
bormant
Нет. Операция ^ -- разыменование указателя -- не применяется к числу.
А ASCIIZ -- это последовательность из символов, оканчивающаяся символом с кодом 0.
ps. Забудьте пока про стек в памяти, вы употребляется эти слова не к месту.
Re: cdecl - как это работает и для чего это?
Добавлено: 24.03.2013 23:34:00
vitaly_l
Только не пугайтесь такому вопросу (если такое невозможно) - просто мне нужно понять... Хотя наверно это чушь... Я просто пытаюсь интерпретировать это как номер строки стэка в памяти... (забывая что у стэка есть только начало и конец) Просто вот эта строчка не укладывается в моём понимании: (PChar(Data) + Size - 1)^.... для меня это число... точнее адрес в памяти.
Спасибо дальше я найду в поиске..
Добавлено спустя 5 минут 12 секунд:bormant писал(а):Забудьте пока про стек в памяти, вы употребляется эти слова не к месту
Просто у меня нет ясного понимания что именно делает такой код... Поэтому я спрашивал, чтобы отсечь лишнее.
К данным типа pchar с помощью операции сложения можно добавлять целые значения, что соответствует смещению начала ASCIIZ-строки на указанное число позиций. Аналогично выполняется операция вычитания.
Re: cdecl - как это работает и для чего это?
Добавлено: 24.03.2013 23:39:17
bormant
Тот стек, о котором шла речь в соглашениях о вызове -- это особенность процессоров, имеющих регистр указатель стека (SP -- stack pointer) и набор команд по работе с ним, причем в их состав входят и команды вызова/возврата -- адрес возврата сохраняется на стеке во время вызова подпрограмм.
По поводу число/не число. Указатель на ячейку памяти в конечном итоге тоже является числом -- адресом этой ячейки. Вот только размер и структура этого адреса не всегда однозначно ложится на те или иные целые типы, да и семантика от указателей требуется несколько иная, например в части инкремента/декремента.
Re: cdecl - как это работает и для чего это?
Добавлено: 24.03.2013 23:43:28
vitaly_l
bormant писал(а):По поводу число/не число.
Я нашёл - Вы смещали начало ASCIIZ-строки на указанное число позиций, а потом закончили строку присвоив #0; <== правильно?
Вот пример, если кто столкнётся с подобной "дилеммой".
Код: Выделить всё
const
pch1: pchar = 'hello world';
pch2: pchar = 'привет мир';
var
p_str: pchar;
n: longint;
begin
p_str := pch1 + 6;
writeln(p_str); // world
writeln(pch2 + 7); // мир
p_str := 'This is world';
writeln(p_str);
n := pch2 - pch1;
writeln(n);
readln
end.
Re: cdecl - как это работает и для чего это?
Добавлено: 25.03.2013 10:04:41
debi12345
(PChar(Data) + Size - 1)^ := #0
А разве "-1" здесь правильно ? "+Size" как раз указывает на следующий за последним байтом данных.
Re: cdecl - как это работает и для чего это?
Добавлено: 25.03.2013 11:02:51
alexey38
vitaly_l писал(а):запускается TReadCallback из вот такой функции.
LoadFromStream(Stream: TStream; ReadCallback: TReadCallback; UserData: Pointer): LongWord;
Вы похоже залезли в дебри сами не желая этого, и у Вас получилась каша из особенностей программирования на ассемблере до форматов файлов. Это полезно изучать, но нужно не в куче, а последовательно. Интересует стек, значить изучайте стек, причем есть работа со стеком на уровне ассемблера, а есть стек, как удобная для некоторых алгоритмов форма хранения данных, в т.ч. применяемая на паскале. Принцип один и тот же, но назначение разное. Одно Вы можете знать, но не влияете на это. А другое Вы можете использовать, если это Вам надо.
В Вашем случае важно, чтобы когда Вы вызываете функцию LoadFromStream, то во втором параметре Вы указали адрес функции, имеющей тоже тип cdecl.
Приведите фактический пример из Вашей программы вызова LoadFromStream, а также фактический пример из Вашей программы, где описана процедура, указанная по втором параметре.
Re: cdecl - как это работает и для чего это?
Добавлено: 25.03.2013 12:00:23
vitaly_l
debi12345 писал(а):А разве "-1" здесь правильно ? "+Size" как раз указывает на следующий за последним байтом данных.
Он там прибавлял единицу, поэтому теперь отнимает - всё правильно.
Добавлено спустя 5 минут 51 секунду:alexey38 писал(а): и у Вас получилась каша из особенностей программирования
Мы просто общались и пришли к определённому результату.
Я просто ищу решение.
.
Re: cdecl - как это работает и для чего это?
Добавлено: 25.03.2013 12:04:05
bormant
debi12345 писал(а):А разве "-1" здесь правильно ?
Если бы Size = Length(s), то вы были бы правы, но там было написано
Код: Выделить всё
Size := Length(s) + 1;
GetMem(Data, Size);
Move(s[1], Data^, Size - 1);
(PChar(Data) + Size - 1)^ := #0;
Re: cdecl - как это работает и для чего это?
Добавлено: 25.03.2013 17:02:33
vitaly_l
В общем cdecl - у меня начал работать...
В смысле результат тестового текстового файла вывелся в TMemo через с-декларацию cdecl...
Получается что, к cdecl - должна быть "приклеена" @функция... как в примерах, доброго bormant'a.
Либо получается что, нужна Dll, как говорит добрый debi12345.
Суть в том что, у меня не текстовый файл, а форматированный и dll никаких нет...
И @функций, как в примерах bormant'a, в модуле тоже нет... и обращение там без @FunctionName. Но файл же как-то открывался?
И в описании к модулю написано что, файл - должен открываться без dll и он на 50% считывается модулем, кроме кусочков с cdecl.
В data - лежат банальные координаты (таинственного острова..., а там капитан Немо... Хреново быть художником... Вокруг уже море... чайки.. я на острове... где-то здесь капитан Немо... пойду искать Наутилус...
.
Добавлено спустя 3 часа 11 минут 28 секунд:
Спиральная раковина Наутилуса диаметром 15—23 см разделена на 35—38 камер, последовательно соединённых длинным сифоном. Моллюск живёт в передней, самой большой камере. Раковина используется как поплавок и балласт. Нагнетая в камеры раковины биогаз, или откачивая его из них, наутилус способен всплывать к поверхности воды или погружаться в её толщу. Некоторые наутилусы жили на Земле пятьсот миллионов лет назад...)
Спасибо всем!