How to Convert Between Hexadecimal and Decimal in Batch Script (Hex to Dec and viceversa)
While batch scripting primarily uses decimal (base-10) numbers for its arithmetic operations via set /a
, interactions with external systems, configuration files, registry entries, or low-level data often involve hexadecimal (base-16) values. Being able to seamlessly convert numbers between these two bases directly within your batch scripts is a powerful capability for automation and data manipulation.
This guide will provide two robust batch script subroutines:
:toDec
for converting hexadecimal strings to their decimal equivalents,- and
:toHex
for converting decimal integers (positive or negative) into their 32-bit hexadecimal string representations.
We'll break down how each script works and show you how to integrate them into your own batch files.
Why Convert Between Hexadecimal and Decimal in Batch?
- Hexadecimal (Hex): Base-16, uses digits
0-9
and lettersA-F
. Common for representing memory addresses, color codes, data flags, error codes, and in various low-level computing contexts. - Decimal (Dec): Base-10, the standard number system for everyday use and for most arithmetic operations within batch scripts (
set /a
).
The need for conversion arises when:
- You receive hexadecimal input (e.g., from a command output, file, or registry) that needs to be used in decimal-based calculations or comparisons within your batch script.
- You have a decimal value that needs to be formatted or sent as a hexadecimal string to an external program, API, or configuration.
Converting Hexadecimal to Decimal (:toDec
)
This subroutine takes a hexadecimal string and converts it to its decimal integer equivalent.
The :toDec
Subroutine Script
@echo off
REM --- Main script example area ---
CALL :toDec "FF" result_decimal
ECHO Hex FF is Decimal: %result_decimal%
CALL :toDec "1A3" another_decimal
ECHO Hex 1A3 is Decimal: %another_decimal%
ECHO Hex B is Decimal:
CALL :toDec "B"
ECHO ---
REM --- End of main script example, use GOTO :EOF or EXIT /B for real scripts ---
GOTO :EOF
:toDec hex dec -- convert a hexadecimal number to decimal
:: -- hex [in] - hexadecimal number to convert
:: -- dec [out,opt] - variable to store the converted decimal number in
SETLOCAL
set /a dec_value=0x%~1
( ENDLOCAL & REM RETURN VALUES
IF "%~2" NEQ "" (SET %~2=%dec_value%) ELSE ECHO.%dec_value%
)
EXIT /b
Output:
Hex FF is Decimal: 255
Hex 1A3 is Decimal: 419
Hex B is Decimal:
11
How :toDec
Works: set /a
with the 0x
Prefix**
The conversion is elegantly handled by the set /a
command, which is batch's arithmetic evaluator.
set /a dec_value=0x%~1
:%~1
: Takes the first argument passed to the subroutine (the hex string, e.g.,FF
) and removes any surrounding quotes.0x%~1
: Prefixes the hex string with0x
(e.g.,0xFF
).- When
set /a
encounters a number prefixed with0x
, it automatically interprets it as a hexadecimal value and converts it to its decimal representation for the assignment. So,0xFF
is internally converted to decimal255
, which is then stored indec_value
.
Usage Examples for :toDec
-
Store result in a variable:
CALL :toDec "C8" myDecVar
ECHO Value of C8 is %myDecVar%Output:
Value of C8 is 200
-
Direct output (echo):
ECHO Decimal for 20 (hex):
CALL :toDec "20"Output:
Decimal for 20 (hex):
32
Limitations of :toDec
- Input Validation: The script doesn't rigorously check if the input is a valid hex string. Invalid hex characters might be treated as
0
byset /a
, or cause an error if the string is completely unparseable byset /a
's hex parser. - Number Size:
set /a
operates on 32-bit signed integers. Hexadecimal values representing numbers outside the approximate range of -2,147,483,648 to 2,147,483,647 might lead to incorrect results or wrap-around behavior. For typical 8-bit to 32-bit hex values (e.g.,00
toFFFFFFFF
), this is generally suitable.
Converting Decimal to Hexadecimal (:toHex
)
This subroutine converts a decimal integer (positive or negative) into its 32-bit, 8-character hexadecimal string representation.
The :toHex
Subroutine Script
@echo off
REM --- Main script example area ---
CALL :toHex 255 result_hex_FF
ECHO Decimal 255 is Hex: %result_hex_FF%
CALL :toHex -1 result_hex_neg1
ECHO Decimal -1 is Hex: %result_hex_neg1%
ECHO Hex for 42 is:
CALL :toHex 42
ECHO ---
REM --- End of main script example, use GOTO :EOF or EXIT /B for real scripts ---
GOTO :EOF
: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
SETLOCAL ENABLEDELAYEDEXPANSION
set /a dec_input_val=%~1
set "hex_output_str="
set "hex_map=0123456789ABCDEF"
for /L %%N in (1,1,8) do (
set /a "current_nibble=dec_input_val&15,dec_input_val>>=4"
for %%D in (!current_nibble!) do set "hex_output_str=!hex_map:~%%D,1!!hex_output_str!"
)
rem !!!! To remove leading zeros (e.g., 1A instead of 0000001A), uncomment the next line.
rem for /f "tokens=* delims=0" %%A in ("!hex_output_str!") do (set "hex_output_str=%%A" & if not defined hex_output_str set "hex_output_str=0")
( ENDLOCAL & REM RETURN VALUES
IF "%~2" NEQ "" (SET %~2=%hex_output_str%) ELSE ECHO.%hex_output_str%
)
EXIT /b
Output:
Decimal 255 is Hex: 000000FF
Decimal -1 is Hex: FFFFFFFF
Hex for 42 is:
0000002A
---
How :toHex
Works: Bitwise Operations, Mapping, and Delayed Expansion
SETLOCAL ENABLEDELAYEDEXPANSION
: Essential because variables (current_nibble
,hex_output_str
) are modified and read within theFOR
loop. Delayed expansion (!variable!
) allows accessing the current runtime value of a variable inside a code block.set /a dec_input_val=%~1
: Ensures the input decimal is treated as a 32-bit signed integer.hex_map=0123456789ABCDEF
: A lookup string that maps decimal values 0-15 to their hexadecimal character representations.for /L %%N in (1,1,8) do (...)
: This loop runs exactly 8 times, once for each of the 8 hexadecimal digits (nibbles) in a 32-bit integer.set /a "current_nibble=dec_input_val&15,dec_input_val>>=4"
: This is the core calculation, performing two operations at once:dec_input_val&15
: A bitwise AND with 15 (binary1111
) isolates the lowest 4 bits ofdec_input_val
. This gives a decimal value from 0 to 15, which is the value of the current hex digit (nibble). The result is stored incurrent_nibble
.dec_input_val>>=4
: This performs a bitwise arithmetic right shift ondec_input_val
by 4 positions. This discards the 4 bits we just processed and prepares the next 4 bits for the next loop iteration. For negative numbers, this correctly propagates the sign bit, maintaining the proper two's complement representation.
for %%D in (!current_nibble!) do set "hex_output_str=!hex_map:~%%D,1!!hex_output_str!"
: This is a classic batch trick used because you cannot directly use one variable as an index for a substring operation on another variable (e.g.,!hex_map:~!current_nibble!,1!
is invalid).!current_nibble!
: Gets the 0-15 value calculated in the previous step.- The
FOR %%D
loop iterates just once, with its variable%%D
taking on the value of!current_nibble!
. !hex_map:~%%D,1!
: Now that the numeric value is in%%D
, we can use it to extract one character from thehex_map
. For example, ifcurrent_nibble
is10
,%%D
becomes10
, and this extracts'A'
.- The new hex character is prepended to
hex_output_str
. This correctly builds the final hex string because we are processing nibbles from least significant (rightmost) to most significant (leftmost).
Understanding the 32-bit Hexadecimal Output and Optional Leading Zero Removal
This script generates an 8-character hexadecimal string, representing the full 32-bit integer value.
- Positive numbers will have leading zeros (e.g., decimal 26 becomes
0000001A
). - Negative numbers are represented in their 32-bit two's complement form (e.g., decimal -1 becomes
FFFFFFFF
). The commented-out linerem for /f "tokens=* delims=0" %%A_val in ("!hex_output_str!") do ...
can be uncommented (removerem
) to strip these leading zeros for positive numbers, resulting in, for example,1A
instead of0000001A
. It also handles the case where the result is0
.
Usage Examples for :toHex
- Store result in a variable:
Output:
CALL :toHex 4095 myHexVar
ECHO Decimal 4095 is Hex: %myHexVar%Decimal 4095 is Hex: 00000FFF
- Direct output (echo):
Output:
ECHO Hex for 160:
CALL :toHex 160Hex for 160:
000000A0
Key Batch Scripting Concepts Used in Both Subroutines
SETLOCAL
and ENDLOCAL
for Scope Management
These commands are crucial for creating modular subroutines. SETLOCAL
starts a new environment scope. Variables created or modified within this scope are local and do not affect the caller's environment, unless explicitly passed back. ENDLOCAL
discards this local scope.
Parameter Handling (%~1
, %~2
)
Batch subroutines receive arguments as positional parameters: %1
for the first, %2
for the second, and so on. The ~
modifier (e.g., %~1
) removes any surrounding quotation marks from the passed argument, which is useful for handling inputs that might be quoted.
"Returning" Values from Subroutines
Batch doesn't have direct function return statements like other languages. Values are typically "returned" by:
- Setting an environment variable in the caller's scope. This is achieved by the
( ENDLOCAL & IF "%~2" NEQ "" (SET %~2=%value_to_return%) ...)
construct. The assignmentSET %~2=%value_to_return%
happens afterENDLOCAL
but within the same command processing block, allowing it to affect the parent environment. ECHO
ing the value to standard output, which the caller can capture if needed (e.g., using aFOR /F
loop). Both subroutines do this if an output variable name is not provided.
Conclusion: A Complete Hex-Decimal Conversion Toolkit
These two subroutines, :toDec
and :toHex
, provide a powerful and self-contained toolkit for converting numbers between hexadecimal and decimal representations directly within your Windows Batch scripts.
:toDec
leveragesset /a
's built-in understanding of the0x
prefix for straightforward hex-to-decimal conversion.:toHex
employs bitwise arithmetic and string manipulation with delayed expansion to convert decimal numbers (including negatives via two's complement) to their 32-bit hexadecimal string form.
By understanding their mechanisms and how to call them, you can greatly enhance the numerical processing capabilities of your batch scripts when dealing with these common number bases.