有谁知道 Delphi 的 C/C++ printf的 100% 克隆?是的,我知道系统。格式化函数,但它处理的事情有点不同。
例如,如果要将 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 _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;
不建议使用 (ws)printf ,因为它们容易出现缓冲区溢出,最好使用安全的变体(例如StringCchPrintF)。它已经在 Jedi Apilib (JwaStrSafe) 中声明。
好吧,我刚刚找到了这个:
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 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 App 进行交叉编译。使用 coredll.dll 而不是 msvcrt.dll