Page 4 of 5
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 12:55 pm
by luis
wilbert wrote:
Probably the x64 calling convention.
But it does the same on x86
Code: Select all
ImportC ""
swprintf(*str.string,format.s,*args1=0,*args2=0)
EndImport
Global str.s{128}
Global i = 12
Global f.f = 3.14
; FLD dword [v_f]
; PUSH eax
; FISTP dword [esp]
; PUSH dword [v_i]
; MOV eax,_S1
; PUSH eax
; PUSH dword v_str
; CALL _swprintf
swprintf(@str,"test %i %f",i, f) ; test 12 0.000000
Debug str
If I'm not mistaken it just pushes the two 32 bits quantities on the stack, so shouldn't %f interpret the 32 bit data as a float ?
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 1:55 pm
by wilbert
luis wrote:If I'm not mistaken it just pushes the two 32 bits quantities on the stack, so shouldn't %f interpret the 32 bit data as a float ?
FISTP stores the float as an integer which won't work.
But there also seems to be a bug on PureBasic Windows x64.
I can't get swprintf to work cross platform so here's an example with sprintf instead.
Code: Select all
ImportC ""
sprintf(*str, format.p-ascii, arg1.d=0, arg2.d=0)
EndImport
Global Dim buf.a(128)
sprintf(@buf(), "test %f", 3.14)
Debug PeekS(@buf(), -1, #PB_Ascii)
sprintf(@buf(), "test %f %f", 3.14, Sqr(2))
Debug PeekS(@buf(), -1, #PB_Ascii)
This code should work cross platform but doesn't on Windows x64.
On a 64 bit platform, the floating point arguments need to be passed by XMM0 and XMM1 but it looks like PB Windows x64 uses the wrong XMM registers

Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 2:33 pm
by luis
wilbert wrote:
FISTP stores the float as an integer which won't work.
Woops, thanks. I misunderstood the difference between FSTP and FISTP. That explain why we can't just use all integers in the prototype and make it work for floats/doubles too.
But why even specifying float instead of integer in the prototype doesn't work ?
Code: Select all
; Win x86
ImportC ""
sprintf_with_float (*str.string,format.s,args1, f.f) As "_swprintf" ; does not work using the right type ?
sprintf_with_double (*str.string,format.s,args1, f.d) As "_swprintf" ; work using double ?
EndImport
Global str.s{128}
Global i = 12
Global f.f = 3.14 ; this is a float
sprintf_with_float (@str,"test %i %f",i, f) ; test 12 0.000000 ; ZERO ?
Debug str
sprintf_with_double (@str,"test %i %f",i, f) ; test 12 3.140000
Debug str
sprintf_with_double (@str,"test %i %lf",i, f) ; test 12 3.140000
Debug str
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 2:59 pm
by wilbert
luis wrote:But why even specifying float instead of integer in the prototype doesn't work ?
From what I've read online when it comes to C,
float arguments to variadic function are promoted to double.
So for a function like sprintf / swprintf, you always need to use a double when importing the function or using PrototypeC.
After that, passing a float (.f) works fine as PB will convert it to a double.
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 3:07 pm
by luis
float arguments to variadic function are promoted to double.
Oh, didn't know that, thanks very much Wilbert, now at least I've got an explanation for that.
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 3:08 pm
by pthien
wilbert wrote:luis wrote:But why even specifying float instead of integer in the prototype doesn't work ?
From what I've read online when it comes to C,
float arguments to variadic function are promoted to double.
So for a function like sprintf / swprintf, you always need to use a double when importing the function or using PrototypeC.
After that, passing a float (.f) works fine as PB will convert it to a double.
I've used this code, obviously not with 64-bit code handling floating-point types, though.
I just wonder if someone us going to post fixed code when the discussion of what is wrong is concluded and a universal solution identified?

Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 3:14 pm
by skywalk
Code: Select all
ImportC ""
_snprintf(*sRes.p-Ascii, nBytes.i, sFmt.p-Ascii, sTxt.p-Ascii, NumToFmt.d)
EndImport
Global.i nBytes = #MAX_PATH
Global sRes.s = Space(nBytes)
_snprintf(@sRes, nBytes, "%s %6.6e", "Result = ", -#PI*2000e6)
Debug PeekS(@sRes, -1, #PB_Ascii)
[/url]This function call works on PB v562 x64.
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 3:29 pm
by wilbert
skywalk wrote:This function call works on PB v562 x64.
You are right but I still believe there's a bug as this doesn't work
Code: Select all
ImportC ""
_snprintf(*sRes.p-Ascii, nBytes.i, sFmt.p-Ascii, NumToFmt.d)
EndImport
Global.i nBytes = #MAX_PATH
Global sRes.s = Space(nBytes)
_snprintf(@sRes, nBytes, "%6.6e", -#PI*2000e6)
Debug PeekS(@sRes, -1, #PB_Ascii)
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 5:30 pm
by skywalk
Yes, the bug is confusing
Code: Select all
ImportC ""
_snprintf(*sRes.p-Ascii, nBytes.i, sFmt.p-Ascii, sTxt.p-Ascii, a2.d)
_snprintf1(*sRes.p-Ascii, nBytes.i, sFmt.p-Ascii, a2.d) As "_snprintf"
EndImport
Global.i nBytes = #MAX_PATH
Global sRes.s = Space(nBytes)
_snprintf(@sRes, nBytes, "%s %6.6e", "Result = ", -#PI*2000e6)
Debug PeekS(@sRes, -1, #PB_Ascii)
_snprintf1(@sRes, nBytes, "%6.6e", -#PI*2000e6)
Debug PeekS(@sRes, -1, #PB_Ascii)
Re: Format string with some values like sprintf (C) - Update
Posted: Thu Jul 19, 2018 8:34 pm
by mk-soft
First:
C-LIB not support float, only double
Second:
Please open a new topic for C-LIB printf... -> Link:
viewtopic.php?f=13&t=71083
Thanks

Re: Format string with some values like sprintf (C) - Update
Posted: Wed Jul 19, 2023 1:35 pm
by AZJIO
Can leading zeros be added?
Code: Select all
EnableExplicit
XIncludeFile "Format.pbi"
Define y = 2023, m = 7, d = 5, h = 8, i = 45, s = 9
Debug Format("%04i-%02i-%02i", @y, @m, @d)
Debug Format("%02i:%02i:%02i", @h, @i, @s)
Debug Format("%04i-%02i-%02i %02i:%02i:%02i", @y, @m, @d, @h, @i, @s)
I found how to do it. It would be nice to have examples in the first post.
Code: Select all
Define y = 2008, m = 4, d = 1, h = 8, i = 45, s = 9
Debug Format("%04i-%'02i-%'02i", @y, @m, @d)
Debug Format("%'02i:%'02i:%'02i", @h, @i, @s)
Debug Format("%'04i-%'02i-%'02i %'02i:%'02i:%'02i", @y, @m, @d, @h, @i, @s)
Re: Format string with some values like sprintf (C) - Update
Posted: Wed Jul 19, 2023 2:40 pm
by pthien
I added leading zeros by defining "pad" as a space (default), and then changing pad to "0" should the width parameter be preceded by a zero.
My code is probably terrible I lifted this from this very thread and modified it, but here it is:
Code: Select all
Macro __Format__(text, max, pad)
If max
If max < 0
max = ~max
max + 1
If Len(text) <= max
text = LSet(text, max, pad)
EndIf
Else
If Len(text) <= max
text = RSet(text, max, pad)
EndIf
EndIf
EndIf
EndMacro
Procedure.s Format(text.s, *value1 = 0, *value2 = 0, *value3 = 0, *value4 = 0, *value5 = 0, *value6 = 0, *value7 = 0, *value8 = 0, *value9 = 0, *value10 = 0, *value11 = 0)
Protected zeiger, *value, pos1, pos2, len1, len2, exit
Protected type, result.s, help.s, Format.s
Protected is_op = #False
Protected pad.s = " "
zeiger = @*value1
result = text
result = ReplaceString(result, "\r", #CR$)
result = ReplaceString(result, "\n", #LF$)
result = ReplaceString(result, "\t", #TAB$)
result = ReplaceString(result, "\\", "\")
Repeat
pos1 = FindString ( result, "%", pos1 )
If pos1
*value = PeekL ( zeiger )
pos2 = pos1 + 1
exit = #False
Repeat
type = Asc ( Mid ( result, pos2, 1 ) )
is_op = #False
Select type
Case 98, 119, 108, 113, 102, 100, 115 ; "b", "w", "l", "q", "f", "d", "s"
Format = Mid ( result, pos1 + 1, pos2 - pos1 - 1 )
len1 = Val ( StringField ( Format, 1, "." ) )
len2 = Val ( StringField ( Format, 2, "." ) )
is_op = #True
EndSelect
Select type
Case 98
help = Str ( PeekB ( *value ) ) ; "b"
Case 119
help = Str ( PeekW ( *value ) ) ; "w"
Case 108
help = Str ( PeekL ( *value ) ) ; "l"
Case 113
help = Str ( PeekQ ( *value ) ) ; "q" (StrQ depricated so changed to Str)
Case 102
help = StrF ( PeekF ( *value ), len2 ) ; "f"
Case 100
help = StrD ( PeekD ( *value ), len2 ) ; "d"
Case 115
help = PeekS ( *value ) ; "s"
Case 37
help = "%"
result = Left ( result, pos1 - 1 ) + Mid ( result, pos2, Len(result)) ; "%"
Case 43, 45, 46 ; "-" "+" "."
pos2 + 1
Case 49 To 57 ; "1" "2" "3" "4" "5" "6" "7" "8" "9"
pos2 + 1
Case 48 ; "0"
pos2 + 1
pad = "0"
Default
exit = #True
EndSelect
If is_op = #True
__Format__( help, len1, pad )
result = Left ( result, pos1 - 1 ) + help + Mid ( result, pos2 + 1, Len(result))
zeiger + 4
exit = #True
EndIf
Until exit
pos1 + Len ( help )
Else
Break
EndIf
ForEver
ProcedureReturn result
EndProcedure
Re: Format string with some values like sprintf (C) - Update
Posted: Wed Jul 19, 2023 4:49 pm
by AZJIO
Code: Select all
Define d.d = 123.5e-20
Debug Format("%d", @d)
Returns 0.
Re: Format string with some values like sprintf (C) - Update
Posted: Wed Jul 19, 2023 5:01 pm
by pthien
AZJIO wrote: Wed Jul 19, 2023 4:49 pm
Code: Select all
Define d.d = 123.5e-20
Debug Format("%d", @d)
Returns 0.
Looks like you're gonna have to dig in.
Are the earlier examples in this thread working properly with doubles? It should be easy to change the padding character if so.
Re: Format string with some values like sprintf (C) - Update
Posted: Wed Jul 19, 2023 7:13 pm
by ebs
AZJIO wrote: Wed Jul 19, 2023 4:49 pm
Code: Select all
Define d.d = 123.5e-20
Debug Format("%d", @d)
Returns 0.
I assume that you have to specify the number of decimal places for floating point numbers:
Code: Select all
Define v.d = 123.5e-20
Debug Format("%1.22d", @v)
results in '0.0000000000000000012350'