德尔福中的sprintf?

发布于 2024-08-26 05:49:39 字数 397 浏览 12 评论 0原文

有谁知道 Delphi 的 C/C++ printf 的 100% 克隆吗? 是的,我知道 System.Format 函数,但它可以处理一些事情有点不同。

例如,如果要将 3 格式化为“003”,则在 C 中需要“%03d”,但在 Delphi 中需要“%.3d”。

我有一个用 Delphi 编写的应用程序,它必须能够使用 C 格式字符串格式化数字,那么您知道这方面的代码片段/库吗?

提前致谢!

Does anyone know a 100% clone of the C/C++ printf for Delphi?
Yes, I know the System.Format function, but it handles things a little different.

For example if you want to format 3 to "003" you need "%03d" in C, but "%.3d" in Delphi.

I have an application written in Delphi which has to be able to format numbers using C format strings, so do you know a snippet/library for that?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

花开浅夏 2024-09-02 05:49:39

您可以使用 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;

You could use the wsprintf() function from Windows.pas. Unfortunately this function is not declared correctly in the Windows.pas so here is a redeclaration:

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;
柠檬 2024-09-02 05:49:39

如果你想让这个函数看起来对用户来说对 Delphi 更友好,你可以使用以下代码:

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;

If you want to let the function look more Delphi friendly to the user, you could use the following:

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;
你穿错了嫁妆 2024-09-02 05:49:39

不建议使用 (ws)printf 因为它们容易出现缓冲区溢出,最好使用安全变体(例如 StringCchPrintF)。它已经在 J​​edi Apilib (JwaStrSafe) 中声明。

It's not recommended to use (ws)printf since they are prone to buffer overflow, it would be better to use the safe variants (eg StringCchPrintF). It is already declared in the Jedi Apilib (JwaStrSafe).

少钕鈤記 2024-09-02 05:49:39

好吧,我刚刚找到了这个:

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

它只是使用 msvcrt.dll 中的原始 sprintf 函数,然后可以像这样使用它:

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

我不知道这是否是最好的解决方案,因为它需要这个外部dll 并且您必须手动设置字符串的长度,这使得它容易出现缓冲区溢出,但至少它可以工作......有更好的想法吗?

Well, I just found this one:

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

It simply uses the original sprintf function from msvcrt.dll which can then be used like that:

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

I don't know if this is the best solution because it needs this external dll and you have to set the string's length manually which makes it prone to buffer overflows, but at least it works... Any better ideas?

小苏打饼 2024-09-02 05:49:39

则更干净的方法,无需不必要的类型转换

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

more clean approach without unnecessary type casting

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;

If you happen to cross compile for Windows CE App. use coredll.dll instead of msvcrt.dll

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文