Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.05.10;
Скачать: CL | DM;

Вниз

wvsprintf и размер буфера для нее   Найти похожие ветки 

 
Тыщ   (2008-04-25 18:31) [0]

Как узнать, какой велечины буфер будет требоваться функции wvsprintf?

Если это невозможно, посоветуйте замену wvsprintf с совместимыми правилами форматирования (%s, %d, %.14g и т.п.).


 
Игорь Шевченко ©   (2008-04-25 19:36) [1]


> посоветуйте замену


Format ?


> Как узнать, какой велечины буфер будет требоваться функции
> wvsprintf?


Это ее возвращаемое значение


 
Тыщ   (2008-04-25 20:14) [2]

Игорь Шевченко ©   (25.04.08 19:36) [1]

> Format ?

Все бы хорошо, да только в программе ожидается такой же вид параметров, что и у wvsprintf...

> Это ее возвращаемое значение

В том и странность, что это значение возвращается уже после того, как строка записана. И если буфер был недостаточно велик, получим либо AV, либо порчу памяти.


 
palva ©   (2008-04-25 23:26) [3]

В MSDN пишут, что максимум заполнения буфера 1024.


 
Тыщ   (2008-04-26 08:49) [4]

palva ©   (25.04.08 23:26) [3]

Спасибо.

Пните в сторону того, как на стеке выглядят параметры для wvsprintf?
Хочу написать конверсию параметров для другой функции.


 
Игорь Шевченко ©   (2008-04-26 11:04) [5]

Тыщ   (25.04.08 20:14) [2]


> В том и странность, что это значение возвращается уже после
> того, как строка записана. И если буфер был недостаточно
> велик, получим либо AV, либо порчу памяти.


передать nil в качестве буфера не помогает ? (Сам не пробовал, ничего не могу сказать)


> Пните в сторону того, как на стеке выглядят параметры для
> wvsprintf?


+0 адрес возврата
+4 строка формата
+8 параметр1
+12 параметр2
...


 
palva ©   (2008-04-26 13:48) [6]


> передать nil в качестве буфера не помогает ? (Сам не пробовал,
>  ничего не могу сказать)

Я вчера попробовал, у меня не получилось. Было исключение по защите.


> +0 адрес возврата
> +4 строка формата
> +8 параметр1
> +12 параметр2


Эта функция имеет фиксированное число параметров. Последний параметр является адресом области памяти, содержащей величины, которые интерпретируются в соответствии с форматной строкой. Я попробовал следующий код:

{$APPTYPE CONSOLE}
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 адрес области параметров


 
Тыщ   (2008-04-26 19:56) [7]

Я так понял, что любой параметр всегда будет занимать 4 байта?
Числа с плавающей точкой будут всегда приводиться в single, или передаваться с помощью указателя?
Строки - с помощью указателя?

Со всем остальным понятно, спасибо.


 
palva ©   (2008-04-26 20:38) [8]

> Я так понял, что любой параметр всегда будет занимать 4 байта?
Ну да, хотя в документации я не видел такого описания.
Параметры должны выглядеть так же, как будто они были бы положены в стек при вызове функции printf в языке си. Что произойдет с плавающими, я не знаю, поскольку не в курсе о наличии соответствующих форматов и не могу проверить. А символы и строки - да.

{$APPTYPE CONSOLE}
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); // 42334543 q zxcv
end.


 
Тыщ   (2008-04-26 23:12) [9]

Спасибо за пример.

Выяснил, что числа с плавающей точкой будут занимать 8 байт, в том числе и в стеке, то есть тип - double.
А также, что wvsprintf не работает с ними - выводит буковку.
А вот vsprintf из msvcrt.dll - работает.

{$APPTYPE CONSOLE}
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";

{$A4}
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); // 42334543 q zxcv DEADBEEF f g
 vsprintf(a, fmt, @rec.i);
 WriteLn(" vsprintf: " + a); // 42334543 q zxcv DEADBEEF 1.010000 1.01
end.


P.S. в Win98 wvsprintf даже указатель не выводит.


 
Leonid Troyanovsky ©   (2008-04-27 10:03) [10]


> Тыщ   (26.04.08 23:12) [9]

>  в том числе и в стеке, то есть тип - double.
> А также, что wvsprintf не работает с ними - выводит буковку.

А чего, wvsprintf обязан работать с float?

--
Regards, LVT.


 
Тыщ   (2008-04-27 10:23) [11]

Leonid Troyanovsky ©   (27.04.08 10:03) [10]
> А чего, wvsprintf обязан работать с float?

По идее да, если эта функция позиционируется, как "Win32 Equivalent for C Run-Time Function".


 
Leonid Troyanovsky ©   (2008-04-27 10:44) [12]


> Тыщ   (27.04.08 10:23) [11]

> По идее да, если эта функция позиционируется, как "Win32
> Equivalent for C Run-Time Function".

Не всякому рантайму потребны float.
Что там в msdn написано насчет возможных форматов?
Кста, arglist - это, IMHO, указатель на массив поинтеров.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2008-04-27 10:53) [13]


> Leonid Troyanovsky ©   (27.04.08 10:44) [12]

> Кста, arglist - это, IMHO, указатель на массив поинтеров.

Фу-ты, это первый элемент массива поинтеров, sorry.

--
Regards, LVT.


 
Тыщ   (2008-04-27 10:58) [14]

Leonid Troyanovsky ©   (27.04.08 10:44) [12]

> Что там в msdn написано насчет возможных форматов?

Ограниченность wvsprintf там отражена.

> Кста, arglist - это, IMHO, указатель на массив поинтеров.

Да нет же, см. последний пример, указатель на массив разного всего.


 
Игорь Шевченко ©   (2008-04-27 15:41) [15]

palva ©   (26.04.08 13:48) [6]

Пардон, перепутал с wsprintf, буковка v из головы вылетела. В случае с буковкой v все совсем просто - первый аргумент адрес формата, второй аргумент адрес arglist (который va_list, и по которому надо бегать вручную за каждым аргументом, в зависимости от его типа)


 
Тыщ ©   (2008-04-29 13:10) [16]

{$APPTYPE CONSOLE}
uses Windows;

function Int2Str(Value:integer):string;
begin
 Str(Value,Result);
end;

function Int2Hex(Num:integer):string;
asm
 // edx = Pointer to string
 // eax = Num
 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;
// Supported form: %[width][.precision]type
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!";
//const fmt="!%d %c %s %p %.f %.g %f %g %zs!";
begin
 vsprintf(a,fmt,@rec); WriteLn("vsprintf: "+a);
 s:=dprintf(fmt,@rec); WriteLn(" dprintf: "+s);
end.


 
Тыщ ©   (2008-04-29 13:12) [17]

Вот, собственно, написал замену wvsprintf и vsprintf :)
Если кому пригодится - я буду только рад.


 
Игорь Шевченко ©   (2008-04-29 17:50) [18]


> Вот, собственно, написал замену 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 пользовать всяко проще...


 
Тыщ ©   (2008-04-29 18:35) [19]

Игорь Шевченко ©   (29.04.08 17:50) [18]

Да не, rec - это для тестирования.
Писал же для сишной библиотеки, которая ожидает функцию формы (w)vsprintf.


 
Игорь Шевченко ©   (2008-04-29 23:27) [20]

Тыщ ©   (29.04.08 18:35) [19]

А как простому программисту использовать ?


 
Тыщ ©   (2008-04-30 05:42) [21]

Игорь Шевченко ©   (29.04.08 23:27) [20]

Ой, не знаю. Пусть сам решает.



Страницы: 1 вся ветка

Текущий архив: 2009.05.10;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.01 c
2-1238076122
DevilDevil
2009-03-26 17:02
2009.05.10
Глупый вопрос. Путь к bpl.


2-1238506162
Галинка
2009-03-31 17:29
2009.05.10
Где почитать про аггрегатные выборки


2-1238312668
Rom1988
2009-03-29 11:44
2009.05.10
Загрузить файл в TMemoryStream под другим именем


2-1238085390
Вова
2009-03-26 19:36
2009.05.10
Delphi + MySQL


2-1238427650
Brauberg
2009-03-30 19:40
2009.05.10
Поиск и запись в строке