-
Как узнать, какой велечины буфер будет требоваться функции wvsprintf?
Если это невозможно, посоветуйте замену wvsprintf с совместимыми правилами форматирования (%s, %d, %.14g и т.п.).
-
> посоветуйте замену
Format ?
> Как узнать, какой велечины буфер будет требоваться функции > wvsprintf?
Это ее возвращаемое значение
-
Игорь Шевченко © (25.04.08 19:36) [1]
> Format ?
Все бы хорошо, да только в программе ожидается такой же вид параметров, что и у wvsprintf...
> Это ее возвращаемое значение
В том и странность, что это значение возвращается уже после того, как строка записана. И если буфер был недостаточно велик, получим либо AV, либо порчу памяти.
-
В MSDN пишут, что максимум заполнения буфера 1024.
-
palva © (25.04.08 23:26) [3]
Спасибо.
Пните в сторону того, как на стеке выглядят параметры для wvsprintf? Хочу написать конверсию параметров для другой функции.
-
Тыщ (25.04.08 20:14) [2]
> В том и странность, что это значение возвращается уже после > того, как строка записана. И если буфер был недостаточно > велик, получим либо AV, либо порчу памяти.
передать nil в качестве буфера не помогает ? (Сам не пробовал, ничего не могу сказать)
> Пните в сторону того, как на стеке выглядят параметры для > wvsprintf?
+0 адрес возврата +4 строка формата +8 параметр1 +12 параметр2 ...
-
> передать nil в качестве буфера не помогает ? (Сам не пробовал, > ничего не могу сказать)
Я вчера попробовал, у меня не получилось. Было исключение по защите. > +0 адрес возврата > +4 строка формата > +8 параметр1 > +12 параметр2
Эта функция имеет фиксированное число параметров. Последний параметр является адресом области памяти, содержащей величины, которые интерпретируются в соответствии с форматной строкой. Я попробовал следующий код:
function wvsprintf(Output: PChar; Format: PChar; arglist: Pointer): Integer;
stdcall; external 'user32' name 'wvsprintfA';
var
a: array [0..1000] of Char;
ii: array [0..1] of Integer;
begin
ii[0] := 42334543;
ii[1] := 534;
wvsprintf(a, '%d %d', @ii[0]);
WriteLn(a);
ReadLn
end.
+0 адрес буфера с результирующей строкой +4 строка формата +8 адрес области параметров
-
Я так понял, что любой параметр всегда будет занимать 4 байта? Числа с плавающей точкой будут всегда приводиться в single, или передаваться с помощью указателя? Строки - с помощью указателя?
Со всем остальным понятно, спасибо.
-
> Я так понял, что любой параметр всегда будет занимать 4 байта?Ну да, хотя в документации я не видел такого описания. Параметры должны выглядеть так же, как будто они были бы положены в стек при вызове функции printf в языке си. Что произойдет с плавающими, я не знаю, поскольку не в курсе о наличии соответствующих форматов и не могу проверить. А символы и строки - да.
function wvsprintf(Output: PChar; Format: PChar; arglist: Pointer): Integer;
stdcall; external 'user32' name 'wvsprintfA';
var
a: array [0..1000] of Char;
rec: record
i: Integer;
c1: Char;
s: String;
end;
begin
rec.i := 42334543;
rec.c1 := 'q';
rec.s := 'zxcv';
wvsprintf(a, '%d %c %s', @rec.i);
WriteLn(a); end.
-
Спасибо за пример. Выяснил, что числа с плавающей точкой будут занимать 8 байт, в том числе и в стеке, то есть тип - double. А также, что wvsprintf не работает с ними - выводит буковку. А вот vsprintf из msvcrt.dll - работает.
function vsprintf(Output: PChar; Format: PChar; arglist: Pointer): Integer;
cdecl; external 'msvcrt.dll';
function wvsprintf(Output: PChar; Format: PChar; arglist: Pointer): Integer;
stdcall; external 'user32' name 'wvsprintfA';
var
a: array [0..1023] of Char;
rec: record
i: Integer;
c1: Char;
s: String;
p: pointer;
fd: double;
fd2: double;
end=(
i: 42334543;
c1: 'q';
s: 'zxcv';
p: Ptr($DEADBEEF);
fd: 1.01;
fd2: 1.01;
);
const fmt='%d %c %s %p %f %.14g';
begin
wvsprintf(a, fmt, @rec.i);
WriteLn('wvsprintf: ' + a); vsprintf(a, fmt, @rec.i);
WriteLn(' vsprintf: ' + a); end. P.S. в Win98 wvsprintf даже указатель не выводит.
-
> Тыщ (26.04.08 23:12) [9]
> в том числе и в стеке, то есть тип - double. > А также, что wvsprintf не работает с ними - выводит буковку.
А чего, wvsprintf обязан работать с float?
-- Regards, LVT.
-
Leonid Troyanovsky © (27.04.08 10:03) [10] > А чего, wvsprintf обязан работать с float?
По идее да, если эта функция позиционируется, как "Win32 Equivalent for C Run-Time Function".
-
> Тыщ (27.04.08 10:23) [11]
> По идее да, если эта функция позиционируется, как "Win32 > Equivalent for C Run-Time Function".
Не всякому рантайму потребны float. Что там в msdn написано насчет возможных форматов? Кста, arglist - это, IMHO, указатель на массив поинтеров.
-- Regards, LVT.
-
> Leonid Troyanovsky © (27.04.08 10:44) [12]
> Кста, arglist - это, IMHO, указатель на массив поинтеров.
Фу-ты, это первый элемент массива поинтеров, sorry.
-- Regards, LVT.
-
Leonid Troyanovsky © (27.04.08 10:44) [12]
> Что там в msdn написано насчет возможных форматов?
Ограниченность wvsprintf там отражена.
> Кста, arglist - это, IMHO, указатель на массив поинтеров.
Да нет же, см. последний пример, указатель на массив разного всего.
-
palva © (26.04.08 13:48) [6]
Пардон, перепутал с wsprintf, буковка v из головы вылетела. В случае с буковкой v все совсем просто - первый аргумент адрес формата, второй аргумент адрес arglist (который va_list, и по которому надо бегать вручную за каждым аргументом, в зависимости от его типа)
-
uses Windows;
function Int2Str(Value:integer):string;
begin
Str(Value,Result);
end;
function Int2Hex(Num:integer):string;
asm
push esi
push edi
bswap eax
push eax
mov edi,edx
mov esi,esp
mov eax,edx
mov edx,8
call System.@LStrSetLength
mov edi,[edi]
mov ecx,4
@@next:
lodsb
mov ah,al
and al,$0F
cmp al,10
sbb al,$69
das
xchg al,ah
shr al,$04
cmp al,10
sbb al,$69
das
stosw
loop @@next
pop eax
pop edi
pop esi
end;
function Double2Str(D:double; Width,Precision:integer; CutEndZeroes:boolean):string;
var Temp:string;
begin
if not CutEndZeroes then
begin
Str(D:0:Width,Temp);
if Precision<Width*2-Length(Temp) then Precision:=Width*2-Length(Temp);
end else Precision:=15;
Str(D:Width:Precision,Result);
if CutEndZeroes then
begin
while Result[Length(Result)]='0' do Delete(Result,Length(Result),1);
if Result[Length(Result)]='.' then Delete(Result,Length(Result),1);
Insert(StringOfChar(' ',Width-Length(Result)),Result,1);
end;
end;
function vsprintf(Output,Format:pchar; ArgList:pointer):integer;
cdecl; external 'msvcrt.dll';
function dprintf(const Fmt:string; ArgList:pchar):string;
const
FMT_CHAR=['c','d','f','g','p','s'];
FMT_NUM=['0','1','2','3','4','5','6','7','8','9'];
var
I,Width,Precision:integer;
WidthSpecified:boolean;
begin
if Fmt='' then
begin
Result:='';
Exit;
end;
I:=1;
repeat
if Fmt[I]<>'%' then
begin
Result:=Result+Fmt[I];
end else begin
Inc(I);
if I>Length(Fmt) then break;
Width:=0;
WidthSpecified:=false;
Precision:=0;
while Fmt[I] in FMT_NUM do
begin
WidthSpecified:=true;
Width:=Width*10+Ord(Fmt[I])-48;
Inc(I);
if I>Length(Fmt) then Exit;
end;
if Fmt[I]='.' then
begin
Inc(I);
if I>Length(Fmt) then break;
while Fmt[I] in FMT_NUM do
begin
Precision:=Precision*10+Ord(Fmt[I])-48;
Inc(I);
if I>Length(Fmt) then Exit;
end;
end;
if Precision=0 then Precision:=1;
case Fmt[I] of
'c': begin
Result:=Result+ArgList^;
Inc(ArgList,4);
end;
'd': begin
Result:=Result+Int2Str(PInteger(ArgList)^);
Inc(ArgList,4);
end;
'f': begin
if not WidthSpecified then Width:=8;
Result:=Result+Double2Str(PDouble(ArgList)^,Width,Precision,false);
Inc(ArgList,8);
end;
'g': begin
if not WidthSpecified then Width:=1;
Result:=Result+Double2Str(PDouble(ArgList)^,Width,Precision,true);
Inc(ArgList,8);
end;
'p': begin
Result:=Result+Int2Hex(PInteger(ArgList)^);
Inc(ArgList,4);
end;
's': begin
Result:=Result+PChar(Ptr(PInteger(ArgList)^));
Inc(ArgList,4);
end;
else continue;
end;
end;
Inc(I);
until I>Length(Fmt);
end;
var
a: array [0..1023] of Char;
rec: packed record
i: Integer;
c1: Char; _dummy:array[0..2] of byte;
s: String;
p: pointer;
fd: double;
fd2: double;
fd3: double;
fd4: double;
end=(
i: 42334543;
c1: 'q';
s: 'zxcv';
p: Ptr($DEADBEEF);
fd: 1.01;
fd2: 1.01;
fd3: 1.01;
fd4: 1.01;
);
s:string;
const fmt='!%d %c %s %p %5.14f %5.14g %f %g %zs!';
begin
vsprintf(a,fmt,@rec); WriteLn('vsprintf: '+a);
s:=dprintf(fmt,@rec); WriteLn(' dprintf: '+s);
end.
-
Вот, собственно, написал замену wvsprintf и vsprintf :) Если кому пригодится - я буду только рад.
-
> Вот, собственно, написал замену wvsprintf и vsprintf :)
> rec: packed record > i: Integer; > c1: Char; _dummy:array[0..2] of byte; > s: String; > p: pointer; > fd: double; > fd2: double; > fd3: double; > fd4: double; > end=( > i: 42334543; > c1: 'q'; > s: 'zxcv'; > p: Ptr($DEADBEEF); > fd: 1.01; > fd2: 1.01; > fd3: 1.01; > fd4: 1.01; > );
а эту rec каждый раз вручную кодировать ? :) Format пользовать всяко проще...
-
Игорь Шевченко © (29.04.08 17:50) [18]
Да не, rec - это для тестирования. Писал же для сишной библиотеки, которая ожидает функцию формы (w)vsprintf.
-
Тыщ © (29.04.08 18:35) [19]
А как простому программисту использовать ?
-
Игорь Шевченко © (29.04.08 23:27) [20]
Ой, не знаю. Пусть сам решает.
|