I don’t know why but Erlang bit syntax always confused me. I always skipped it while reading the docs, until, well, now that I need it. I should say this is not meant to be an exhaustive how-to by any means. It’s just a collection of notes, but howto sounded better. 🙂 There are better guides out there. [Reference docs too.]
Anyway. Here’s some binary data in Erlang:
What does all this mean? Let’s analyze it, left to right.
16# This specifies we want to express the number in base 16.
- We have an eight digits hex number.
- No type specification is provided: default is unsigned integer.
- No unit specification is provided: default for integer is 1, which means ‘bits’.
:32 Size specification: this tells erlang to consider 32 units, which in our case means 32 bits, since we are dealing with bits.
Let’s evaluate it:
What if we forget to specify the size spec? In that case the default will apply and since we’re dealing with an integer type, the default is 8 (bits). For Erlang this means we are going to return the least significant byte:
Now that we know that, we can get a subset of bits by setting the size accordingly:
<<16,90>> %two least significant bytes
We don’t need to specify a size multiple of 8:
It’s pretty cool how easy it is to slice bytes apart at the bit level. I was sort of surprised that if we slice some internal bits it looks like the bits at the right are moved to the left. E.g. here we take the 4 least significant bits of the first 0xFF:
but instead of obtaining:
F 00 FF 00
F0 0F F0 0 [240 == F0]
Also, the value doesn’t need to be a literal, it can be an expression:
91> N = 16#FF00FF01.
And therefore, given some binary data, we can also pattern-match it super easily:
<SourcePort:16, DestinationPort:16, CheckSum:16, Payload/binary>> = SomeBinary.
There’s more to Erlang bit syntax than this, but I’ll stop here for now.