How can you convert a byte array to a hexadecimal string, and vice versa?
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
- How to know full paths to DLL's from .csproj f
There's a class called SoapHexBinary that does exactly what you want.
This problem could also be solved using a look-up table. This would require a small amount of static memory for both the encoder and decoder. This method will however be fast:
My solution uses 1024 bytes for the encoding table, and 256 bytes for decoding.
Decoding
Encoding
Comparison
* this solution
Note
During decoding IOException and IndexOutOfRangeException could occur (if a character has a too high value > 256). Methods for de/encoding streams or arrays should be implemented, this is just a proof of concept.
From Microsoft's developers, a nice, simple conversion:
While the above is clean an compact, performance junkies will scream about it using enumerators. You can get peak performance with an improved version of Tomolak's original answer:
This is the fastest of all the routines I've seen posted here so far. Don't just take my word for it... performance test each routine and inspect its CIL code for yourself.
Safe versions:
Unsafe versions For those who prefer performance and do not afraid of unsafeness. About 35% faster ToHex and 10% faster FromHex.
BTW For benchmark testing initializing alphabet every time convert function called is wrong, alphabet must be const (for string) or static readonly (for char[]). Then alphabet-based conversion of byte[] to string becomes as fast as byte manipulation versions.
And of course test must be compiled in Release (with optimization) and with debug option "Suppress JIT optimization" turned off (same for "Enable Just My Code" if code must be debuggable).
For performance I would go with drphrozens solution. A tiny optimization for the decoder could be to use a table for either char to get rid of the "<< 4".
Clearly the two method calls are costly. If some kind of check is made either on input or output data (could be CRC, checksum or whatever) the
if (b == 255)...
could be skipped and thereby also the method calls altogether.Using
offset++
andoffset
instead ofoffset
andoffset + 1
might give some theoretical benefit but I suspect the compiler handles this better than me.This is just off the top of my head and has not been tested or benchmarked.
When writing crypto code it's common to avoid data dependent branches and table lookups to ensure the runtime doesn't depend on the data, since data dependent timing can lead to side-channel attacks.
It's also pretty fast.
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn
An explanation of the weird bit fiddling:
bytes[i] >> 4
extracts the high nibble of a bytebytes[i] & 0xF
extracts the low nibble of a byteb - 10
is
< 0
for valuesb < 10
, which will become a decimal digitis
>= 0
for valuesb > 10
, which will become a letter fromA
toF
.i >> 31
on a signed 32 bit integer extracts the sign, thanks to sign extension. It will be-1
fori < 0
and0
fori >= 0
.(b-10)>>31
will be0
for letters and-1
for digits.0
, andb
is in the range 10 to 15. We want to map it toA
(65) toF
(70), which implies adding 55 ('A'-10
).b
from the range 0 to 9 to the range0
(48) to9
(57). This means it needs to become -7 ('0' - 55
).Now we could just multiply with 7. But since -1 is represented by all bits being 1, we can instead use
& -7
since(0 & -7) == 0
and(-1 & -7) == -7
.Some further considerations:
c
, since measurement shows that calculating it fromi
is cheaper.i < bytes.Length
as upper bound of the loop allows the JITter to eliminate bounds checks onbytes[i]
, so I chose that variant.b
an int allows unnecessary conversions from and to byte.