2010-03-18 17 views
5

¿Alguien sabe una clonación del 100% de C/C++ printf para Delphi? Sí, conozco el sistema. Format funciona, pero maneja las cosas un poco diferente.sprintf en Delphi?

Por ejemplo, si desea formatear 3 en "003" necesita "% 03d" en C, pero "% .3d" en Delphi.

Tengo una aplicación escrita en Delphi que tiene que ser capaz de formatear números usando cadenas de formato C, ¿conoces un fragmento/biblioteca para eso?

¡Gracias de antemano!

+0

No puede formatear 3.14 a "003" con "% 03d". – n0rd

+0

Lo sentimos, debería haber sido un entero, reparado;) La pregunta sigue siendo válida :) – kroimon

Respuesta

13

Puede usar la función wsprintf() de Windows.pas. Por desgracia, esta función no se ha declarado correctamente en los windows.pas asi que aquí hay una redeclaración:

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

Wow bien, estaba un poco tarde respondiendo mi propia pregunta;) Gracias, creo que esta es una solución mucho mejor que la importación desde msvcrt .dll! Lo intentaré más tarde ... – kroimon

+0

Después de darme cuenta de que el método 'user32.wsprintf (W | A)' no puede manejar los puntos flotantes, ahora decidí usar 'msvcrt._vsnw? Printf' por ahora usando su vararg-fix abajo. La mejor manera habría sido una versión sin dependencias externas, pero 'msvcrt.dll' debería estar disponible donde sea que lo necesite. – kroimon

1

Bueno, acabo de encontrar esta:

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

Simplemente utiliza la función sprintf original a partir de la cual msvcrt.dll a continuación, se puede utilizar como esa:

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

no sé si esta es la mejor solución, ya que necesita este archivo DLL externa y hay que establecer la cadena de longitud manualmente lo que hace que sea propenso a desbordamientos de búfer, pero al menos funciona ... ¿Alguna idea mejor?

9

Si desea que la función de un aspecto más Delphi amigable para el usuario, se puede utilizar el siguiente:

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 para esta versión sofisticada, ¡gracias! – kroimon

+0

¡Nunca escuché acerca de esto! ¿Cómo lo descubriste, Andreas ??????? –

+0

Al leer la definición de C/C++ - macros va_start, va_list, va_end. –

3

No es recomendable utilizar (WS) printf ya que son propensos al desbordamiento del búfer, se sería mejor usar las variantes seguras (por ejemplo, StringCchPrintF). Ya está declarado en el Jedi Apilib (JwaStrSafe).

+0

Como no quería incluir Jedi solo para esta función, decidí usar '_vsnw? Printf' de' msvcrt.dll', que también debería ser seguro, ya que su segundo parámetro es el tamaño del búfer ... – kroimon

0

enfoque más limpia y sin innecesaria tipo de fundición

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; 

Si le sucede a cruzar compilar la aplicación para Windows CE. use coredll.dll en lugar de msvcrt.dll