有没有人知道Delphi的C/C++ printf的100%克隆? 是的,我知道系统。 Format功能,但它处理的事情有点不同。sprintf在Delphi中?
例如,如果要将3格式设置为“003”,则需要C中的“%03d”,而Delphi中需要“%.3d”。
我有一个用Delphi编写的应用程序,必须能够使用C格式字符串格式化数字,所以你知道一个片段/库吗?
在此先感谢!
有没有人知道Delphi的C/C++ printf的100%克隆? 是的,我知道系统。 Format功能,但它处理的事情有点不同。sprintf在Delphi中?
例如,如果要将3格式设置为“003”,则需要C中的“%03d”,而Delphi中需要“%.3d”。
我有一个用Delphi编写的应用程序,必须能够使用C格式字符串格式化数字,所以你知道一个片段/库吗?
在此先感谢!
您可以使用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;
好吧,我刚刚发现这一个:
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,我不知道这是不是最好的解决办法,你必须设置该字符串的长度手动,这使得它容易缓冲区溢出,但至少它的作品...任何更好的想法?
如果你想让函数看起来更德尔福友好的用户,可以使用下列内容:
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;
+1这个复杂的版本,谢谢! – kroimon 2010-03-18 18:14:28
我从来没有听说过这个!你是如何发现的,Andreas ??????? – 2010-10-28 16:48:56
通过阅读C/C++ - 宏va_start,va_list,va_end的定义。 – 2010-10-29 07:16:38
它不推荐,因为他们很容易缓冲区溢出来使用(WS)的printf,它最好使用安全变体(例如StringCchPrintF)。它已经在Jedi Apilib(JwaStrSafe)中声明。
因为我不想仅仅为这个函数包含Jedi,所以我决定使用'msvcrt.dll'中的'_vsnw?printf',它应该是安全的,因为它的第二个参数是缓冲区大小... – kroimon 2010-03-22 10:37:38
避免不必要的类型转换
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
使用“%03d”无法将3.14格式化为“003”。 – n0rd 2010-03-18 17:25:02
对不起,应该是一个整数,固定;)问题仍然有效:) – kroimon 2010-03-18 17:29:54