Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

wvsprintf и размер буфера для нее


Страницы:   1 2

Тыщ ©   (2008-04-25 18:31:00) 

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

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


Тыщ   (2008-04-30 05:42:00) [1]

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

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


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

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

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


Тыщ   (2008-04-29 18:35:00) [3]

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

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


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


> Вот, собственно, написал замену 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 13:12:00) [5]

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


Тыщ   (2008-04-29 13:10:00) [6]

{$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-27 15:41:00) [7]

palva ©   (26.04.08 13:48) [6]

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


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

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

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

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

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

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


Leonid Troyanovsky   (2008-04-27 10:53:00) [9]


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

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

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

--
Regards, LVT.


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


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

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

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

--
Regards, LVT.


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

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

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


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


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

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

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

--
Regards, LVT.


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

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

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


palva   (2008-04-26 20:38:00) [14]

> Я так понял, что любой параметр всегда будет занимать 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 19:56:00) [15]

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

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


palva   (2008-04-26 13:48:00) [16]


> передать 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 11:04:00) [17]

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


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


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


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


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


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

palva ©   (25.04.08 23:26) [3]

Спасибо.

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


palva   (2008-04-25 23:26:00) [19]

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


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

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

> Format ?

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

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

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо