• Welcome to Jose's Read Only Forum 2023.
 

Convert a value to binary string

Started by Pierre Bellisle, January 11, 2023, 08:18:24 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Pierre Bellisle

I have a need for converting values to binary string.
Assembler would be ideal.
I did not find anything in the o2 examples folders nor in this forum.
I was a good time to refresh the little I know in asm.
I came up with this.
It's a first, I will have to do not only dword but byte to qword, also I have to do a 64 bit version.
I think I can do something with typeof to have the function accept any type of variable...
Fun to learn...
Any suggestion will be appreciated...


include once "D:\Dev\Oxygen\o2\inc\MinWin.inc"
include once "D:\Dev\Oxygen\o2\inc\console.inc"
include once "D:\Dev\Oxygen\o2\~code\myInc\WinConsts.inc"
'_____________________________________________________________________________

function DwToBinString32(byval doubleword as dword) as string

string sBin[32] = "00000000000000000000000000000000"

push eax            'Save registry
push ebx            'Save registry
push ecx            'Save registry
push esi            'Save registry

mov eax, doubleword 'set eax with doubleword dword value
mov bl,  49         'set bl to character 49, aka "1"
mov ecx, 32         'set ecx to 32, 32 bit in a dword
addr esi, sBin      'set esi with sBin memory address
add esi, 31         'set the address to the end of sBin
again:              'Looping label for each 32 bit
bt eax,  00         'bit test eax, BitPos 0
jae WasZero         'jump short to WasZero if above or equal, cf = 0
mov [esi], bl       'set "1" at esi address of sBin
WasZero:            'bit was zero jumping label
dec esi             'point to previous character
shr eax, 01         'shift right eax by one bit
loop again          'decrement ecx and loop until ecx = zero, aka: ! dec ecx : cmp ecx, 0 : jnz again

pop esi             'Restore registry
pop ecx             'Restore registry
pop ebx             'Restore registry
pop eax             'Restore registry

return sbin

END FUNCTION
'_____________________________________________________________________________

SetConsoleTitle "dw to binary string"
long BitNess = sizeof(sys) * 8

printl "Compiled at " & BitNess & "bit" : printl
if BitNess = 32 then
   dword doubleword = 0x00000001
   printl "Len DwToBinString() = " len(DwToBinString32(doubleword))
   printl "0x" hex(doubleword, 8) " = " DwToBinString32(doubleword)
   doubleword = 0x80000001
   printl "0x" hex(doubleword, 8) " = " DwToBinString32(doubleword)
   doubleword = 0xF0F00F0F
   printl "0x" hex(doubleword, 8) " = " DwToBinString32(doubleword)
else
   printl "64bit version not coded yet"
endif

printl : printl "Press a key or click to end"
waitkey

end
'_____________________________________________________________________________
'


Charles Pegge

Hi Pierre,

This is the pointer technique I normally use. No need for converter functions or assembler. Sorry :)


'11/01/2023
'binary strings
string s=nuls 256
sys p=strptr s
'map values into the string
int bi at p+4
float bf at p+8
bi=42
bf=21.5
'
'check with numbers in a copy of the string
string t=s
p=strptr t
@bi=p+4
@bf=p+8
print bi "  " bf



Pierre Bellisle

Charles,
This is not exactly what I had in mind.
I was thinking more of something like the BIN$() function in PB.

Still, embedding some variables in a string, copy them to another string
and retreive them seem so natural to o2. Great coding language!

I see that @bi can also be a statement, not just a function.
@bi=p+4 - I'm not used yet to so much versality! I like!

About converting numbers to string: binary, octal, decimal, or hex...
When a coder feel lazy, many APIs can help, the next one is easy to use.


include once "D:\Dev\Oxygen\o2\inc\MinWin.inc"
include once "D:\Dev\Oxygen\o2\inc\console.inc"

// Converts an integer to a string.
! function ui64toa_s  lib "msvcrt.dll" alias "_ui64toa_s" _
(byval quad value, byref zstring buffer, byval dword sizeInCharacters, byval long radix) as long

long Radix, ApiError
quad quadNum     
zstring zStringNumer[66]

quadNum = 0xffffffffffffffff
printl
printl "convert 0x" & hex(quadNum) & " value to"
printl
Radix = 02  : ApiError  = ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "binary  0b " & zStringNumer
Radix = 08  : ApiError += ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "octal   0o " & zStringNumer
Radix = 10  : ApiError += ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "decimal 0d " & zStringNumer
Radix = 16  : ApiError += ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "hex     0x " & zStringNumer
if ApiError then printl "Some error occured, see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/itoa-s-itow-s?view=msvc-170"
printl
printl "Strike a key to end!" : waitkey


Roland Stowasser

#3
Hi Charles,

I tried to be still more lazy and used corewin.inc, I had to declare ui64toa_s nevertheless (unprototyped):

...
// Converts an integer to a string.
! function ui64toa_s  lib "msvcrt.dll" alias "_ui64toa_s"
...

The app seems to work as 32-bit exe and as a 64-bit exe too. Does this mean that my declaration did not override these lines in Msvcrt.inc?:

...
#ifndef mode64bit
  extern lib "Msvcrt.dll" cdecl
#else
  extern lib "Msvcrt.dll"
#endif
...

This is the code with changes:


$ filename "NumToString.exe"
'uses rtl32
'uses rtl64

uses corewin
uses console

// Converts an integer to a string.
! function ui64toa_s  lib "msvcrt.dll" alias "_ui64toa_s"

long Radix, ApiError
quad quadNum     
zstring zStringNumer[66]

quadNum = 0xffffffffffffffff
printl
printl "convert 0x" & hex(quadNum) & " value to"
printl
Radix = 02  : ApiError  = ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "binary  0b " & zStringNumer
Radix = 08  : ApiError += ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "octal   0o " & zStringNumer
Radix = 10  : ApiError += ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "decimal 0d " & zStringNumer
Radix = 16  : ApiError += ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "hex     0x " & zStringNumer

if ApiError then printl "Some error occured, see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/itoa-s-itow-s?view=msvc-170"
printl
printl "Strike a key to end!" : waitkey

Charles Pegge

Hi Roland,

Without cdecl in 32bit compilations, old params will accumulate on the stack when making a cdecl call.. If you are looping over the cdecl call, you will eventually cause a stack  overflow.

To avoid this situation, you can either put the cdecl call inside a wrapper function or explicitly restore the stack register to its prior value:


'universal stack fix: stdcall/cdecl/ms64
sys pstk 'variable to hold stack pointer
...
pstk=rsp 'save stack pointer
'call functions ...
rsp=pstk 'restore stack pointer





Roland Stowasser

Thank you Charles,

I must admit that I do not fully understand how and where I have to include the fix in the above example, but I will try.
My simple solution would be to use the func names which are already declared in Msvcrt.dll e.g.:

...
Radix = 02  : ApiError  = _ui64toa_s(quadNum, zStringNumer, 65, Radix) : PRINTl "binary  0b " & zStringNumer
...

I wondered if it would also be possible to create a sys ui64toa_s as a function pointer to _ui64toa_s?
In any case there are a lot of useful functions in Msvcrt.dll which can be applied.

Charles Pegge

Where the calling convention of a function might be CDECL , the above fix will ensure that the stack pointer is always  restored to its prior value. (without pre-declaring it to be CDECL )

Charles Pegge

Pierre,

Just in case you want to use native o2:

Here is a binstring function which will return the binary string of any number if the byte count is also passed:


function binstring(any*p, int nb=4) as string
=============================================
indexbase 0
string s=nuls nb*8
byte bs at @p       'byte overlay input
byte bt at strptr s 'byte overlay output
int i,j,k,m
nb--
for i=nb to 0 step -1
  byte b=bs[i]
  for j=7 to 0 step -1
    m=k+j
    bt[m]=48+(b and 1) 'ascii 0 or 1
    shr b              'bit shift right
  next
  k+=8
next
return s
end function

int v=0xcc33aaaa
print binstring(v,4) 'pass numeric variable and its byte count

Pierre Bellisle

Great to know about the msvcrt 32/64 cdecl difference.
The binstring() o2 native is a keep-it !

I begin to really like this o2 forum...

Thank you Charles & Roland !

back to learning...