Erlang笔记 -- 二进制与位语法

本文介绍了Erlang中的二进制数据结构,包括二进制型与位串的概念,以及如何使用内置函数和位语法进行操作。重点讲述了如何构建、拆分二进制,以及通过位推导进行位操作。文中还提供了实例,如反转二进制字节顺序和位顺序,帮助理解Erlang中二进制的处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二进制型(binary)是一种数据结构,当二进制型里的位数都会是8的整数倍时,对应一个字节串。当位数不是8的整数倍,则称这段数据为位串(bitstring)。
二进制型的编写和打印形式是双小于号与双大于号之间的一列整数或字符串:

1> <<19,88,20>>.
<<19,88,20>>
2> <<"hello">>.
<<"hello">>
3> <<49,50,51>>.
<<"123">>
4> <<99,97,116>>.
<<"cat">>

在二进制型里使用整数时,它们必须属于0255这个范围。
二进制型<<"cat">><<99,97,116>>的简写形式,这个二进制型是由字符串里这些字符的ASCII编码组成的。
和字符串类似,如果某个二进制型的内容是可打印的字符串,shell就会将这个二进制型打印成字符串,否则就打印成一列整数。
可以用内置函数和位语法来构建二进制型或提取它里面的元素。

1. 内置函数
  • list_to_binary(L) -> B

list_to_binary返回一个二进制型,它是通过把io列表(iolist)L里的所有元素压扁后形成的(压扁的意思是移除列表里所有的括号)。io列表本身是循环定义的,它是指一个列表所包含的元素是0…255的整数、二进制型或者其他io列表。

5> list_to_binary([999,123]). %% 999超出范围0~255
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary([999,123])
6> list_to_binary([<<"abc">>, 123, <<1,2,3>>]).
<<97,98,99,123,1,2,3>>
  • split_binary(Bin, Pos) -> {Bin1, Bin2}
    这个函数在Pos处把二进制型Bin一分为二。
7> split_binary(<<1,2,3,4,5,6,7,8>>, 3).
{<<1,2,3>>,<<4,5,6,7,8>>}
  • term_to_binary(Term) -> Bin
    把任何Erlang数据类型转换成一个二进制型。

  • binary_to_term(Bin) -> Term
    term_to_binary的逆操作。

8> term_to_binary({abc, [1,2,3]}).
<<131,104,2,100,0,3,97,98,99,107,0,3,1,2,3>>
9> binary_to_term(<<131,104,2,100,0,3,97,98,99,107,0,3,1,2,3>>).
{abc,[1,2,3]}
  • byte_size(Bin) -> Size
10> byte_size(<<1,2,3>>).
3
11> byte_size(<<>>).
0
2. 位语法

位语法是一种表示法,用于从二进制数据里提取或加入单独的位或者位串。
它们的形式如下:
<<>>
<<E1, E2, ..., En>>
每个Ei元素都标识出二进制型或位串里的一个片段。单个Ei元素可以有4种形式。

Ei = Value |
     Value:Size |
     Value/TypeSpecifierList |
     Value:Size/TypeSpecifierList

如果表达式的总位数是8的整数倍,就会构建一个二进制型,否则构建一个位串。

构建二进制型时,Value必须是已绑定变量、字符串,或是能得出整数、浮点数或二进制型的表达式。用于模式匹配操作时,Value可以是绑定或未绑定的变量、整数、字符串、浮点数或二进制型。

Size的值指明了片段的大小。它的默认值取决于不同的数据类型,对整数来说是8,浮点数则是64,如果是二进制型就是该二进制型的大小。在模式匹配里,默认值只对最后那个元素有效。如果未指定片段的大小,就会采用默认值。

TypeSpecifierList(类型指定列表)是一个用连字符分隔的列表,形式为End-Sign-Type-Unit。前面这些项中的任何一个都可以被省略,各个项也可以按任意顺序排列。如果省略了某一项,系统就会使用它的默认值。

  • End可以是big|little|native
    它指定机器的字节顺序。native是指在运行时根据机器的CPU来确定。默认值是big,也就是网络字节顺序(network byte order)。
12> {<<16#12345678:32/big>>,<<16#12345678:32/little>>,<<16#12345678:32/native>>,<<16#12345678:32>>}. %% 16# 表示十六进制
{<<18,52,86,120>>,
 <<120,86,52,18>>,
 <<120,86,52,18>>,
 <<18,52,86,120>>}
  • sign可以是signed|unsigned
    这个参数只用于模式匹配。默认值是unsigned

  • Type可以是integer|float|binary|bitstring|bits|utf8|utf16|utf32
    默认值是integer

  • Unit的写法是unit:1|2|...|256
    integerfloatbitstringUnit默认值是1binary则是8utf8utf16utf32类型无需提供值。

13> <<49:8>>.
<<"1">>
14> <<49:8/unit:1>>.
<<"1">>
15> <<49:8/unit:2>>.
<<0,49>>
16> <<49:7>>.
<<49:7>>
17> <<49:7/unit:1>>.
<<49:7>>
18> <<49:7/unit:2>>.
<<0,49:6>>

一个片段的总长度是Size x Unit``bitbinary类型的片段长度必须是8的整数倍。

3. 位推导

位推导和二进制型的关系就像列表推导和列表的关系一样。列表推导遍历列表并返回列表。位推导遍历二进制型并生成列表或二进制型。

19> B = <<16#5f>>. 
<<"_">> %% 16#5f是一个十六进制的常量。shell把它打印成了<<"_">>,因为16#5f是_字符的ASCII编码。
20> [X || <<X:1>> <= B]. %% <<<X:1>>是一个模式,代表1位。
[0,1,0,1,1,1,1,1]
21> [X || <<X:2>> <= B].
[1,1,3,3]
22> << <<X>> || <<X:1>> <= B >>.
<<0,1,0,1,1,1,1,1>>
23> [X || <<X:1>> <- B]. %% 注意是 <= 而不是 <-
** exception error: bad generator <<"_">>

20与22的区别在于20构建了一个包含这些位的列表,而22构建了一个二进制型。

4. 实例
  1. 编写一个函数来反转某个二进制型里的字节顺序。
reverse_bitstring_by_byte(BitString) ->
    ByteList = [Byte || <<Byte:8>> <= BitString],
    ReverseByteList = lists:reverse(ByteList),
    ReverseBitString = list_to_binary(ReverseByteList),
    ReverseBitString.
  1. 编写一个函数来反转某个二进制型所包含的位。
reverse_bitstring_by_bit(BitString) ->
    BitList = [Bit || <<Bit:1>> <= BitString],
    ReverseBitList = lists:reverse(BitList),
    ReverseBitString = list_to_binary(ReverseBitList),
    ReverseBitString1 = << <<Bit:1>> || <<Bit:8>> <= ReverseBitString>>,
    ReverseBitString1.

注:本博客为通过《Erlang程序设计 第二版》学习Erlang时所做的笔记。学习更详细的内容,建议直接阅读《Erlang程序设计 第二版》。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值