build_info_control(SendSeq, RecvSeq, Poll) ->
<<0:1, SendSeq/bitstring, Poll/bitstring, RecvSeq/bitstring>>.
Where the `SendSeq` and `RecvSeq` are 3-bit sequence numbers... say one of them is `<<2:3>>` (0b010) and Poll is a single bit (you can see the format here: https://imgur.com/a/9bVBM0W). This field would then be stuck into a binary representing the entire frame.This could probably be made a littler simpler, though, as I'm still rather new to Erlang.
Note you also do get bit shift operators for cases when they’re an appropriate solution (`bsl` and `bsr`)
[0] ++ sendSeq ++ recvSeq ++ [poll]
say sendSeq was one bit but we still wanted it to take 3 bits:
[0] ++ pad 3 sendSeq ++ poll ++ recvSeq
given some "pad" function defined in a library
The only reason it's "hard" in C is because the operations are induced from what the machine can do efficiently and without "a sufficiently smart compiler".
The entire language is built around pattern matching to the point where it simply wouldn't exist otherwise, and I assume binary protocol handling was a core requirement when the language was designed since it was created for telecom switches.
> say sendSeq was one bit but we still wanted it to take 3 bits:
> [0] ++ pad 3 sendSeq ++ poll ++ recvSeq
In Erlang you could do this to get something padded (or truncated) to the correct size:
<< 2:3 >> ;; corresponds to the 3 bits <<010>>
So you can do something like this to ensure the precise bit size of each field: << 0:1, SendSeq:3, Poll:3, RecvSeq:3>> struct build_info_control
{
unsigned char : 1;
unsigned char SendSeq : 3;
unsigned char Poll : 1;
unsigned char RecvSeq : 3;
};
struct build_info_control control;
control.SendSeq = sendSeq;
control.Poll = true;
control.RecvSeq = recvSeq;
The downside of bit fields is that they are implementation specific---you'll have to check the compiler documentation to see if the bits are specified "most significant bit to least significant bit" or "least significant bit to most significant bit" (if that is indeed, important to the problem).