[How to] dec to hex and hex to dec conversion bat

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Voodooman
Posts: 12
Joined: 25 Sep 2011 07:45

[How to] dec to hex and hex to dec conversion bat

#1 Post by Voodooman » 25 Sep 2011 18:34

I spent entire day searching the way how to convert dec value to hex and back, unfortunately there is no documented way to do it, but there are 2 tricks, which i want to share to help other people avoid googling all day long without success (well success was partial, there was a big messy code which i refused to use):

Dec to hex

the trick is exit code variable, which i found by brute force %=exitcode% in mix with exit command, this is how it works

Code: Select all

call cmd /c exit /b %dec%
set hex=%=exitcode%

Note - %dec%=%errorlevel% in this case!
This is it - somehow, when you use dec value to set errorlevel, this %=exitcode% variable mirrors errolevel value in hex.
You may use substrings like this %=exitcode:~-4,-2% (uses 4 last symbols except last 2).
call cmd /c used to prevent quiting your current script (try to use just exit and see for yourself).
I also tried to call for blank function like this:

Code: Select all

call dectohex %dec%
set hex=%=exitcode%
exit
:dectohex
exit /b %1

but for some reason exitcode appears unset when time comes to set hex value.

Hex to Dec

This trick is simpler and works with set /a like this

set /a dec=0x%hex%

whole magic is in 0x (zero x) prefix, set /a consider everything behind 0x as hex value.
0x5=0x05=0x0005...0x00000005 so you should not really care about leading zeroes. but you can strip them.

I personally using these tricks to convert dec variable in hex and then search and replace them in binary with help of this hex editing tool XVI32 http://www.chmaas.handshake.de/delphi/f ... /xvi32.htm
and this simple script for it, which could be executed from bat with arguments as sets of hex or dec values:

Code: Select all

REPLACE %1 BY %2
EXIT


You may also find useful this trick i use to change hex byte order, since most of binary data in Windows written in reversed byte order :

Code: Select all

call cmd /c exit /b %dec%
set hex=%=exitcode%
SET hexa=!hex:~-2!
SET hexb=!hex:~-4,-2!
SET hexc=!hex:~-6,-4!
set  hexd=!hex:~-8,-6!
set xeh=!hexa!!hexb!hexc!!hexd!


1A 2B 3C 4D >> 4D 3C 2B 1A
Last edited by Voodooman on 26 Sep 2011 09:38, edited 1 time in total.

DosItHelp
Expert
Posts: 239
Joined: 18 Feb 2006 19:54

Re: [How to] dec to hex and hex to dec conversion bat

#2 Post by DosItHelp » 26 Sep 2011 00:02

Voodooman,
Nice trick using %=exitcode% variable.

Wanted to mention that dostips also lists two functions for converting hex to dec and dec to hex:
http://www.dostips.com/DtTipsArithmetic ... tion.toDec
http://www.dostips.com/DtTipsArithmetic ... tion.toHex
:)

Voodooman
Posts: 12
Joined: 25 Sep 2011 07:45

Re: [How to] dec to hex and hex to dec conversion bat

#3 Post by Voodooman » 26 Sep 2011 06:58

Yeah that exactly that big function i refused to use, despite big size of code, also it have mistake.

This is fixed, cleaned version

Code: Select all

:tohex
cls
set /a dec=%~1
set "hex="
set "map=0123456789ABCDEF"
for /L %%N in (1,1,8) do (
   set /a "d=dec&15,dec>>=4"
   for /f %%D in ("!d!") do (
      set "hex=!map:~%%D,1!!hex!"
   )
)
rem for /f "tokens=* delims=0" %%A in ("!hex!") do (
rem   set "hex=%%A"
rem   if not defined hex (set "hex=0")
rem )
if "%~2" neq "" (set %~2=!hex!) else (echo.!hex!)
exit /b 0

!id! in original missed quotation symbols "" and was considered as filename to read strings of instead of string itself, also i removed unnecessary & and endlocal plus replaced all variables % by !, but this function is slower and not so compact anyway)

Btw, i still dont know the how to convert ASCII characters to hex in bat, any tips?

I suppose i can try to use function above and make second map of characters in order as they appear in ASCII table, but how can map specified symbol as hex?

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: [How to] dec to hex and hex to dec conversion bat

#4 Post by dbenham » 26 Sep 2011 10:40

Voodooman wrote:Yeah that exactly that big function i refused to use, despite big size of code, also it have mistake.
...
!id! in original missed quotation symbols "" and was considered as filename to read strings of instead of string itself
The DosTips function works perfectly as originally written. It uses a simple FOR loop, not a FOR /F. As long as !d! never contains wildcard characters * or ? it will always return the original value. Since !d! should be a decimal number, there should never be any wildcards.

Voodooman wrote:also i removed unnecessary & and endlocal plus replaced all variables % by !
And you succeeded in breaking some of the carefully constructed functionality. The function is designed to keep all the temporary variable assignments local to the function where they are invisible to the calling script. The details you thought were unnecessary are used to return a value accross the ENDLOCAL barrier. Read this DosTips Function Tutorial for an excellent explanation of the technique.

Voodooman wrote:but this function is slower and not so compact anyway)
You should do some testing before making such a statement. The %=exitcode% technique is much simpler, but it is not faster. Timings are highly machine dependent, but on every machine I have tested, the function is much faster than the %=exitcode% method. In most situations it doesn't matter, but if you are performing many computations in a loop it could become significant. There is as an even faster macro adaptation of the function on my macro thread: dostips.com/forum/viewtopic.php?f=3&t=1827 (I still wish we could post more than 2 links in one message)

Voodooman wrote:Btw, i still dont know the how to convert ASCII characters to hex in bat, any tips?
There is not a simple method to convert ASCII character to hex, but there is a simple method to go in reverse.

This supports non-control ASCII characters only (extended characters above decimal 127 and control characters are not supported)

Code: Select all

set hex=41
set /a num=0x%hex%
call cmd /c exit /b %num%
set char=%=exitCodeASCII%
echo %char%
The returned value will be the capital A as expected.

I have written pure batch functions (with much help from jeb) to go in either direction that support all decimal codes from 1-255. But given that you don't like the num2hex function because of its size, you probably will like my character conversion functions even less. You can trace the development here: New functions: :chr, :asc, :asciiMap This is a 3 page thread - on the last page is a link to a Google Sites page with the final code. The code contains control characters like <tab> that do not upload well on this site.

Dave Benham

Voodooman
Posts: 12
Joined: 25 Sep 2011 07:45

Re: [How to] dec to hex and hex to dec conversion bat

#5 Post by Voodooman » 26 Sep 2011 12:18

i know about %=exitCodeASCII% but its not the point of my interest, as i need opposite effect :D
Actually your script is exactly what i was thinking about (and just mentioned in some thread nearby without awareness that someone already did this script), but again it seems 2 slow and heavy -

255 for cycles with 255 more for cycles??? How many of them do we have in total, 65025??? I suppose coding some little hex\dec\ascii command line converter in C# or asm would be simpler and more effective and faster. Actually i googled for command line tool like this, but i only found hex2dec by Mark Russinovich, so i have no other choice but to do it in pure bat.
But i prefer external tools, its not a problem to redistribute such tools with bat script or hide it inside any exe container like bat2exe, but im not sure if tools like this exist.
Have your tried to code such tool instead of messing with mapping and 255*255 cycles?

As for !id! im not sure what Os you do use, but for me in Windows 7 !id! always returned "file not found" even without /f, by default "for" uses (something) as filename, not as string itself, and its clearly stated in for /? help, i think you messed something or have non default setting in registry or some older Os.
Im quite certain that "!id!" fixed "file not found" problem of original script.

As for removal of & and endlocal, im aware of what exactly they did, but i consider this "hiding" of variables from calling script unnecessary, actually i consider quite necessary to have access to any variable anytime from any part of script, so this is just the matter of taste and task, thats why i prefer to not use endlocal at all.

Also i think "&" is quite unnecessary too, it have nothing to do with local variables, all it can do is chaining 2 commands in one line, but command1 & command 2 is 100% the same as
command 1
command 2
but second looks more readable and eye friendly)


And how come that reading about 10 lines of text and performing 16 "for" loops with math equation could be faster than twoliner exit /b %dec% & %=exitcode% ?
What kind of speed testings you did to get such an unexpected results?

... wow this marco thread is crazy, i just tried thing like that recently, and come to conclusion that it complicates things to much.
escaping special characters needs to be done careful, any minor miscalculation with one more or less ^ symbol and whole macros is screwed, also syntax like this is quite unreadable and with lack of detailed instructions and explanations many people would not even get the idea how it works, also debuging such type of syntax also extra pain in arse and consuming more time, so i dont think its practical enough, it looks more like a challenge... unfortunately i have too little time to mess with challenges like this, and im more interested getting effective result faster.

Do you know about "lex parsimoniae" principle aka "law of parsimony" or "occam's razor"?

"The simplest solution is usually the best" - thats what lex parsimoniae means, and thats the principle i tend to follow and suggest anyone to follow it too.

Using as little for cycles and if else statements and variables as possible is the best solution.

Also i have my personal principle which dont have name but means this - light-weight, well structured, standardized and eye-friendly code is programmer's best friend that helps to debug and develop things faster and more efficient :lol:

Anyway, back to original topic - is there any simple dec\hex\bin command line convertor exist, or anyone here willing to code one, please?))

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: [How to] dec to hex and hex to dec conversion bat

#6 Post by dbenham » 26 Sep 2011 17:37

voodooman wrote:As for !id! im not sure what Os you do use, but for me in Windows 7 !id! always returned "file not found" even without /f, by default "for" uses (something) as filename, not as string itself, and its clearly stated in for /? help, i think you messed something or have non default setting in registry or some older Os.
Im quite certain that "!id!" fixed "file not found" problem of original script.
I'm not convinced, I suspect you have fooled yourself. I know the code works on XP and Vista, and I suspect it works on Windows 7. I don't have access to Windows 7 yet so I can't test. But I find it hard to believe that a) such a fundamental change has been made to the FOR command and b) no one has reported the change on this forum before.

If what you are saying is true, then this statement should give an error if executed from the command line:

Code: Select all

for %s in (DoesNotExist) do @echo %s
On my machines the above simply echoes DoesNotExist. I believe this should work on Windows 7 as well.

Assuming FOR behavior has not changed since Vista, this statement should give no output and no error:

Code: Select all

for %s in (DoesNotExist*) do @echo %s

Again assuming no change, this statement should generate the error you describe:

Code: Select all

for /f %s in (DoesNotExist) do @echo %s

There is nothing wrong with using FOR /F with quotes, but I still belive the current published function is valid.


voodooman wrote:And how come that reading about 10 lines of text and performing 16 "for" loops with math equation could be faster than twoliner exit /b %dec% & %=exitcode% ?
What kind of speed testings you did to get such an unexpected results?
Exitcode is certainly much simpler for the developer, but not for the computer at execution time. There is a lot of initialization that takes place when a new copy of CMD is instantiated.

You shouldn't need quantitative testing to see the difference - simply run each method 100 times in a FOR /L loop that echoes the result and you will see an obvious difference in the rate at which the numbers flow down the screen.

But I do have quantitative timing macros that I use. Normally I would place the following calls at the top of my batch file to conditionally load the necessary macro libraries in case they haven't already been loaded:

Code: Select all

if not defined macro\load.macroLib_Time call macroLib_Time
if not defined macro\load.macroLib_Num call macroLib_Num

But here is a self-contained script that times how long it takes to run each method n times. The script takes one argument that specifies the number of times to test each method. Each method will produce an xxxxx.out file in case you want to compare the outputs. (They are all identical)

Note - you don't need to CALL CMD.EXE - you can simply execute CMD directly within your script. The CALL statement is surprisingly relatively slow.

test.bat

Code: Select all

@echo off
::=========================================================================
::BEGIN DEFINITION OF MACROS
::
setlocal disableDelayedExpansion
set LF=^


::Above 2 blank lines are required - do not remove
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set "echo=echo("
set macro_Call=for /f "tokens=1-26" %%a in

set macro.GetTime=do (%\n%
  setlocal enableDelayedExpansion%\n%
  set "t=0"%\n%
  for /f "tokens=1-4 delims=:." %%A in ("!time: =0!") do set /a "t=(((1%%A*60)+1%%B)*60+1%%C)*100+1%%D-36610100"%\n%
  for %%v in (!t!) do endlocal^&if "%%~a" neq "" (set "%%~a=%%v") else %echo%%%v%\n%
)

set macro.DiffTime=do (%\n%
  setlocal enableDelayedExpansion%\n%
  set /a "DD=(%%~b)-(%%~a)"%\n%
  if !DD! lss 0 set /a "DD+=24*60*60*100"%\n%
  set /a "HH=DD/360000, DD-=HH*360000, MM=DD/6000, DD-=MM*6000, SS=DD/100, DD-=SS*100"%\n%
  if "!HH:~1!"=="" set "HH=0!HH!"%\n%
  if "!MM:~1!"=="" set "MM=0!MM!"%\n%
  if "!SS:~1!"=="" set "SS=0!SS!"%\n%
  if "!DD:~1!"=="" set "DD=0!DD!"%\n%
  for %%v in (!HH!:!MM!:!SS!.!DD!) do endlocal^&if "%%~c" neq "" (set "%%~c=%%v") else %echo%%%v%\n%
)

set macro.Num2Hex=do (%\n%
  setlocal enableDelayedExpansion%\n%
  set /a "dec=(%%~a)"%\n%
  if defined hex set "hex="%\n%
  set "map=0123456789ABCDEF"%\n%
  for /l %%n in (1,1,8) do (%\n%
    set /a "d=dec&15,dec>>=4"%\n%
    for %%d in (!d!) do set "hex=!map:~%%d,1!!hex!"%\n%
  )%\n%
  for %%v in (!hex!) do endlocal^&if "%%~b" neq "" (set "%%~b=%%v") else %echo%%%v%\n%
)
::
::END DEFINITION OF MACROS
::==========================================================================

setlocal enableDelayedExpansion
%echo%
%echo%Measuring how long it takes to execute each method %~1 times
%echo%

%macro_call% ("t1") %macro.GetTime%
(
  for /l %%n in (1 1 %1) do (
    call cmd /c exit /b %%n
    echo !=exitcode!
  )
)>callExitcode.out
%macro_call% ("t2") %macro.GetTime%
%macro_Call% ("t1 t2 time_callExitcode") %macro.DiffTime%

%macro_call% ("t1") %macro.GetTime%
(
  for /l %%n in (1 1 %1) do (
    cmd /c exit /b %%n
    echo !=exitcode!
  )
)>exitcode.out
%macro_call% ("t2") %macro.GetTime%
%macro_Call% ("t1 t2 time_exitcode____") %macro.DiffTime%

%macro_call% ("t1") %macro.GetTime%
(
  for /l %%n in (1 1 %1) do call :toHex %%n
)>function.out
%macro_call% ("t2") %macro.GetTime%
%macro_Call% ("t1 t2 time_function____") %macro.DiffTime%

%macro_call% ("t1") %macro.GetTime%
(
  for /l %%n in (1 1 %1) do %macro_call% ("%%n") %macro.Num2Hex%
)>macro.out
%macro_call% ("t2") %macro.GetTime%
%macro_Call% ("t1 t2 time_macro_______") %macro.DiffTime%

set time_
exit /b


:toHex dec hex -- convert a decimal number to hexadecimal, i.e. -20 to FFFFFFEC or 26 to 0000001A
::             -- dec [in]      - decimal number to convert
::             -- hex [out,opt] - variable to store the converted hexadecimal number in
::Thanks to 'dbenham' dostips forum users who inspired to improve this function
:$created 20091203 :$changed 20110330 :$categories Arithmetic,Encoding
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
set /a dec=%~1
set "hex="
set "map=0123456789ABCDEF"
for /L %%N in (1,1,8) do (
    set /a "d=dec&15,dec>>=4"
    for %%D in (!d!) do set "hex=!map:~%%D,1!!hex!"
)
rem !!!! REMOVE LEADING ZEROS by activating the next line, e.g. will return 1A instead of 0000001A
rem for /f "tokens=* delims=0" %%A in ("%hex%") do set "hex=%%A"&if not defined hex set "hex=0"
( ENDLOCAL & REM RETURN VALUES
    IF "%~2" NEQ "" (SET %~2=%hex%) ELSE ECHO.%hex%
)
EXIT /b

Here is the screen output when using a repeat value of 1000:

Code: Select all

D:\temp>test 1000

Measuring how long it takes to execute each method 1000 times

time_callExitcode=00:00:14.03
time_exitcode____=00:00:12.32
time_function____=00:00:05.72
time_macro_______=00:00:02.02

D:\temp>


voodooman wrote:... wow this marco thread is crazy, i just tried thing like that recently, and come to conclusion that it complicates things to much.
escaping special characters needs to be done careful, any minor miscalculation with one more or less ^ symbol and whole macros is screwed, also syntax like this is quite unreadable and with lack of detailed instructions and explanations many people would not even get the idea how it works, also debuging such type of syntax also extra pain in arse and consuming more time, so i dont think its practical enough, it looks more like a challenge... unfortunately i have too little time to mess with challenges like this, and im more interested getting effective result faster
Macro development is definitely tricky for all of the reasons you state. But once a library of routines is complete and tested, they are very easy to use, and the performance gains can be stunning. Running a moderately complex traditional script can be painful on a slow network drive, yet it can still zip right along if macros are used. I've seen more than a 30 fold speed improvement. Still, I agree they are probably not of interest except to a minority of hard core batch programmers.

Dave Benham

jeb
Expert
Posts: 1042
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: [How to] dec to hex and hex to dec conversion bat

#7 Post by jeb » 02 Oct 2011 09:05

Hi,
The problem of the char to ASCII-code function of iterating over all charactars can be solved with a mapping variable.

Code: Select all

set map=0#301#312#32...a#41
Set tmp=!map:*%ch%#=!
Set /a code=0x!tmp:~0,2!


jeb

Post Reply