2010-03-18 187 views
5

有没有人知道Delphi的C/C++ printf的100%克隆? 是的,我知道系统。 Format功能,但它处理的事情有点不同。sprintf在Delphi中?

例如,如果要将3格式设置为“003”,则需要C中的“%03d”,而Delphi中需要“%.3d”。

我有一个用Delphi编写的应用程序,必须能够使用C格式字符串格式化数字,所以你知道一个片段/库吗?

在此先感谢!

+0

使用“%03d”无法将3.14格式化为“003”。 – n0rd 2010-03-18 17:25:02

+0

对不起,应该是一个整数,固定;)问题仍然有效:) – kroimon 2010-03-18 17:29:54

回答

13

您可以使用Windows.pas中的wsprintf()函数。不幸的是在Windows.pas所以这里这个函数未声明是正确一个重声明:

function wsprintf(Output: PChar; Format: PChar): Integer; cdecl; varargs; 
    external user32 name {$IFDEF UNICODE}'wsprintfW'{$ELSE}'wsprintfA'{$ENDIF}; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    S: String; 
begin 
    SetLength(S, 1024); // wsprintf can work only with max. 1024 characters 
    SetLength(S, wsprintf(PChar(S), '%s %03d', 'Hallo', 3)); 
end; 
+3

哇,好吧,我有点太晚回答我自己的问题;) 谢谢,我认为这是一个比从msvcrt导入更好的解决方案.dll文件!稍后尝试一下...... – kroimon 2010-03-18 17:49:46

+0

在意识到'user32.wsprintf(W | A)'方法无法处理浮点数后,我现在决定使用'msvcrt._vsnw?printf'现在使用您的可变参数修订下面。最好的方式应该是没有外部依赖的版本,但msvcrt.dll应该在我需要的任何地方都可用。 – kroimon 2010-03-22 09:30:16

1

好吧,我刚刚发现这一个:

function sprintf(S: PAnsiChar; const Format: PAnsiChar): Integer; 
    cdecl; varargs; external 'msvcrt.dll'; 

它只是使用原来的sprintf函数从msvcrt.dll其中然后可以使用这样的:

procedure TForm1.Button1Click(Sender: TObject); 
var s: AnsiString; 
begin 
    SetLength(s, 99); 
    sprintf(PAnsiChar(s), '%d - %d', 1, 2); 
    ShowMessage(S); 
end; 

,因为它需要这个外部DLL,我不知道这是不是最好的解决办法,你必须设置该字符串的长度手动,这使得它容易缓冲区溢出,但至少它的作品...任何更好的想法?

9

如果你想让函数看起来更德尔福友好的用户,可以使用下列内容:

function _FormatC(const Format: string): string; cdecl; 
const 
    StackSlotSize = SizeOf(Pointer); 
var 
    Args: va_list; 
    Buffer: array[0..1024] of Char; 
begin 
    // va_start(Args, Format) 
    Args := va_list(PAnsiChar(@Format) + ((SizeOf(Format) + StackSlotSize - 1) and not (StackSlotSize - 1))); 
    SetString(Result, Buffer, wvsprintf(Buffer, PChar(Format), Args)); 
end; 

const // allows us to use "varargs" in Delphi 
    FormatC: function(const Format: string): string; cdecl varargs = _FormatC; 


procedure TForm1.Button1Click(Sender: TObject); 
begin 
    ShowMessage(FormatC('%s %03d', 'Hallo', 3)); 
end; 
+0

+1这个复杂的版本,谢谢! – kroimon 2010-03-18 18:14:28

+0

我从来没有听说过这个!你是如何发现的,Andreas ??????? – 2010-10-28 16:48:56

+0

通过阅读C/C++ - 宏va_start,va_list,va_end的定义。 – 2010-10-29 07:16:38

3

它不推荐,因为他们很容易缓冲区溢出来使用(WS)的printf,它最好使用安全变体(例如StringCchPrintF)。它已经在Jedi Apilib(JwaStrSafe)中声明。

+0

因为我不想仅仅为这个函数包含Jedi,所以我决定使用'msvcrt.dll'中的'_vsnw?printf',它应该是安全的,因为它的第二个参数是缓冲区大小... – kroimon 2010-03-22 10:37:38

0

避免不必要的类型转换

function sprintf(CharBuf: PChar; const Format: PAnsiChar): Integer; 
cdecl; varargs; external 'msvcrt.dll'; 

procedure TForm1.Button1Click(Sender: TObject); 
var CharBuf: PChar; 
begin 
    CharBuf:=StrAlloc (99); 
    sprintf(CharBuf, 'two numbers %d - %d', 1, 2); 
    ShowMessage(CharBuf); 
    StrDispose(CharBuf); 
end; 

更清洁的方式如果发生交叉编译为Windows CE应用程序。使用coredll.dll代替msvcrt.dll