1

例如<<1, 0, 110, 64>>,给定任何二进制文件,我们如何确定是否设置了特定位?

假设我们希望确定是否设置了bit-1bit-2,人们希望这可以工作,但它没有:

<<bit1::bits-size(1), bit2::bits-size(1), _rest::bits>> = <<1, 0, 110, 64>>

给出:

iex(5)> {bit1, bit2}                                                                
{<<0::size(1)>>, <<0::size(1)>>}

正确答案来自 Igor 和其他评论):

<<_::bits-6, bit2::bits-1, bit1::bits-1, num::bits>> = <<1, 0, 110, 64>>

给出预期的答案:

{bit1,bit2} = {1, 0}

背景

我正在构建一个解析器来处理这个问题:https ://msdn.microsoft.com/en-us/library/vs/alm/dd943386(v=office.12).aspx

使用这个 C# 代码作为模板,我得到了正确的结果:<<1, 0, 110, 64>> = 2.4

https://github.com/ChiangHanLung/PIC_VDS/blob/f96afdd3863f5ce1df237b2784040624bc88b16b/Reference_DLL_SourceCode/NPOI/HSSF/Util/RKUtil.cs#L33-L74

我对上述的等效 Elixir 实现按预期工作,但我相信使用位串解析应该是可能的(并且更清洁)

def rk_number(data) do
    # IO.puts " ** rk-data: #{inspect data}"

    n0 = :binary.decode_unsigned(data, :little)
    n1 = n0 >>> 2

    n2 =
      if (n0 &&& 0x2) == 0x2 do # bit-2, is an int
        <<v::little-signed-32>> = <<n1::little-32>>
        v
      else
        n3 = n1 <<< 34
        <<v::little-float-64>> = <<n3::little-64>>
        v
      end

    if (n0 &&& 0x1) == 0x1 do # bit-1, div by 100
      n2 / 100
    else
      n2
    end
  end
4

2 回答 2

3

这是因为默认情况下,<<1, 0, 110, 64>>表示中的每个数字都有大小8

这就是为什么

<<bit1::bits-size(1), bit2::bits-size(1), _rest::bits>> = <<1, 0, 110, 64>>
{bit1, bit2} = {<<0::size(1)>>, <<0::size(1)>>}

因为( ) 中1的2 个第一位等于。size 8000000010

<<bit1::bits-size(8), bit2::bits-size(8), _rest::bits>> = <<1, 0, 110, 64>>
{bit1, bit2} = {<<1>>, <<0>>}

或者

<<bit1::bits-size(1), bit2::bits-size(1), _rest::bits>> = <<1::size(1), 0::size(1), 110, 64>>
{bit1, bit2} = {<<1::size(1)>>, <<0::size(1)>>}      

如果有一个整数,并且你试图获取它的前两位,你可以尝试这样的事情:

<<bit1::bits-size(1), bit2::bits-size(1), _rest::bits>> = :binary.encode_unsigned(your_integer)
于 2017-08-17T09:58:02.733 回答
0

在考虑上述评论之一后,我得到了答案:

<<_::bits-6, bit2::bits-1, bit1::bits-1, num::bits>> = <<1, 0, 110, 64>>

{bit1, bit2} = {1, 0}

这给出了预期的结果

于 2017-08-17T10:23:43.700 回答