关于erlang的binary

比特语法的规格说明
<<>>
<<E1,...,En>>

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

 

Type= integer | float | binary | bytes | bitstring | bits | utf8 | utf16 | utf32(默认值是整型)

Signedness= signed | unsigned  (整型值时有意义,默认是unsigned)

Endianness= big | little | native 默认是big

Unit= unit:IntegerLiteral

  unit是每个数据段的size,允许的取值范围是1..256
  size和unit的乘积是数据占用的二进制位数,且必须可以被8整除
  unit 通常用来保证字节对齐.


bytes是binary简写形式;bits是bitstring的简写形式.

         类型说明二进制数据如何使用,数据的使用方式决定了数据的意义



Unit取值范围是1..256, integer float bitstring默认值是1,binary默认值是8. utf8, utf16, and utf32不需要指定类型规格说明.

Size指定数据段的单位(unit).默认值和类型有关:整型-8位 浮点型-64位

Endianness默认值是big;大端小端只有是Type是整形,utf16,utf32,float的时候有意义.这个决定了二进制数据如何读取.还有一种是选择native选项,这个是运行时根据CPU的情况选择大端还是小端.

数据区所占用bit位数的计算方法:  Size * unit =bit 位数

1
2
3
4
5
6
<<25:4/unit:8>> .
<<0,0,0,25>>
7>  <<25:2/unit:16>> .
<<0,0,0,25>>
8>  <<25:1/unit:32>> .
<<0,0,0,25>>

  


TypeSpecifierList类型规格说明列表使用中横线连接(-).任何省略类型规格说明的都会使用默认值.




对于上面的规格说明,会有两个问题:

 【问题1】Type里面提到了utf8 utf16 utf32,翻阅文档可以看到下面的说明,这些说明怎么理解?

For the utf8, utf16, and utf32 types, Size must not be given. The size of the segment is implicitly determined by the type and value itself.

For utf8, Value will be encoded in 1 through 4 bytes. For utf16, Value will be encoded in 2 or 4bytes. Finally, for utf32, Value will always be encoded in 4 bytes.

 【问题2】endianness 是什么?什么是 big-endian?什么是little-endian?
Native-endian means that the endianness will be resolved at load time to be either big-endian or little-endian,
depending on what is native for the CPU that the Erlang machine is run on. Endianness only matters when the Type is either integer, utf16, utf32, or float. The default is big.
 

 第一个问题:

  还是从头理一下这个问题吧,感谢维基百科详尽的讲解:

   一个字节byte有8位表达256种状态,我们最熟悉的ASCII(American Standard Code for Information Interchange)是最通用的单字节编码系统规定了128个字符和二进制数据位之间的关系,由于只需要一个字节的后面7位就可以实现所以最前面一位为0;并没有。在Erlang中我们可以通过$符号取字符的ASCII值.维基百科ASCII: http://zh.wikipedia.org/wiki/Ascii

      从维基百科中的描述可以看到ASCII的局限性,它的表达能力仅限于现代英语,对于其它语言表达能力是显然不足的。首先被想到的就是利用默认的最高位来表达更多符号,这样做的结果就是0-127表示的符号是相同的,128~256根据语言不同表示的符号不同。这种简单的扩展方案被称为EASCII,它勉强可以表达西欧语言。EASCII的故事看这里:http://zh.wikipedia.org/wiki/EASCII

    看到EASCII方案的时候很容易想到中文字符的表达,中文字符数量巨大,一个字节显然是无能为力的表达的。中文编码我们最熟悉的是GB2312编码,它使用两个字节表达了6763个汉字覆盖了中国大陆99.75%的使用字,人名和古汉语中的罕见字以及繁体字是没有覆盖到的,这也就催生了GBK GB18030编码。记得我们大学同学里有一个叫孟龑的,“龑”字就不在GB2312'名录中。GB2312的八卦看这里:http://zh.wikipedia.org/wiki/Gb2312

     同样的二进制数据按照不同的编码规范去解析得出的符号结果也是不同的,如果使用错误的编码方式去解读就会出现乱码,一个理想的解决方案就是采用一种统一的编码规范。Unicode(统一码、万国码、单一码、标准万国码)是计算机科学领域里的一项业界标准,用以统一地体现和处理世界上大部分的文字系统,并为其编码。读过前面的资料,这里可能产生一个疑问:Unicode会使用几个字节表示字符呢?Unicode只规定符号的编码,不规定如何表达。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF),UTF-8就是转换格式之一。

  UTF-8采用变长字节存储Unicode.如果一个仅包含基本7位ASCII字符的Unicode文件,如果每个字符都使用2字节的原Unicode编码传输,其第一字节的8位始终为0。这就造成了比较大的浪费。对于这种情况,可以使用UTF-8编码,这是一种变长编码,它将基本7位ASCII字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他Unicode字符混合的情况,将按一定算法转换,每个字符使用1-3个字节编码,并利用首位为0或1进行识别。这样对以7位ASCII字符为主的西文文档就大大节省了编码长度(具体方案参见UTF-8)。Unicode 编码:http://zh.wikipedia.org/wiki/Unicode UTF-8编码:http://zh.wikipedia.org/wiki/UTF-8

   这里第一问题的答案已经有了,
由于是变长编码,类型和值决定了占用的字节数。顺便提一下曾经遇到过的文件生成时BOM的问题:

   什么是BOM?字节顺序记号(英语:byte-order mark,BOM)是位于码点U+FEFF的统一码字符的名称。当以UTF-16或UTF-32来将UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其字节序。它常被用来当做标示文件是以UTF-8、UTF-16或UTF-32编码的记号。这里有篇文章已经讨论C#解决BOM的问题(如何读,写,去掉BOM):http://www.cnblogs.com/mgen/archive/2011/07/13/2105649.html

第二个问题:

   维基百科上关于Endianness的资料:http://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F 比较有意思的是它的词源来自于格列佛游记。小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论,争论的双方分别被称为Big-endians和Little-endians。1980年,Danny Cohen在其著名的论文"On Holy Wars and a Plea for Peace"中,为平息一场关于字节该以什么样的顺序传送的争论,而引用了该词。

Endianness字节序,又称端序,尾序。在计算机科学领域中,字节序是指存放多字节数据的字节(byte)的顺序,典型的情况是整数在内存中的存放方式和网络传输的传输顺序。Endianness有时候也可以用指位序(bit)。

一般而言,字节序指示了一个UCS-2字符的哪个字节存储在低地址。如果LSByte在MSByte的前面,即LSB为低地址,则该字节序是小端序;反之则是大端序。在网络编程中,字节序是一个必须被考虑的因素,因为不同的处理器体系可能采用不同的字节序。在多平台的代码编程中,字节序可能会导致难以察觉的bug。网络传输一般采用大端序,也被称之为网络字节序,或网络序。IP协议中定义大端序为网络字节序。

   回到Erlang文档中的那段文字我们就可以理解了:网络字节序采用big-endians,erlang比特语法字节序默认值也是big,也就是说在做网络协议实现的时候我们不需要显示指定该选项。Native-endian的意思是运行时决定字节序。

  字节序的问题是一个公共问题,看老赵的这篇文章:浅谈字节序(Byte Order)及其相关操作

最后贴一段Erlang群里面常问到的一个问题,如何解析从二进制数据中解析字符串:

复制代码
read_string(Bin) ->
    case Bin of
        <<Len:16, Bin1/binary>> ->
            case Bin1 of
                <<Str:Len/binary-unit:8, Rest/binary>> ->
                    {binary_to_list(Str), Rest};
                _R1 ->
                    {[],<<>>}
            end;
        _R1 ->
            {[],<<>>}
    end.
复制代码


An Essay on Endian Order(一篇关于字节序的文章)

http://people.cs.umass.edu/~verts/cs32/endian.html
Copyright (C) Dr. William T. Verts, April 19, 1996

依赖于你使用  computing system,你将不得不考虑多字节数据存储的字节序,特别是当你将数据写到一个文件中时。有两种可选字节序  "Little Endian" and "Big Endian"

Depending on which computing system you use, you will have to consider the byte order in which multibyte numbers are stored, particularly when you are writing those numbers to a file. The two orders are called "Little Endian" and "Big Endian".

The Basics

"Little Endian" 是指低字节存储在低内存地址上,高字节存储在高内存地址上。如一个4字节的longint 4个字节的在内存中的存放顺序。
"Little Endian" means that the low-order byte of the number is stored in memory at the lowest address, and the high-order byte at the highest address. (The little end comes first.) For example, a 4 byte LongInt

    Byte3 Byte2 Byte1 Byte0

will be arranged in memory as follows:

    Base Address+0   Byte0
    Base Address+1   Byte1
    Base Address+2   Byte2
    Base Address+3   Byte3
 
因特尔处理器(在pc机上)用的是"Little Endian"

Intel processors (those used in PC's) use "Little Endian" byte order.

"Big Endian"是指高字节存储在低内存地址上,低字节存储在高内存低地址上,如longint的存储。

"Big Endian" means that the high-order byte of the number is stored in memory at the lowest address, and the low-order byte at the highest address. (The big end comes first.) Our LongInt, would then be stored as:

    Base Address+0   Byte3
    Base Address+1   Byte2
    Base Address+2   Byte1
    Base Address+3   Byte0

摩托罗拉处理器(用在mac上的)用的就是 "Big Endian" 

Motorola processors (those used in Mac's) use "Big Endian" byte order.

Which is Better?
你可能看到很多关于这两种字节序的相对的优点。大多讨论是基于pc和mac的相对优点。这两种风格有自己的优缺点。
You may see a lot of discussion about the relative merits of the two formats, mostly religious arguments based on the relative merits of the PC versus the Mac. Both formats have their advantages and disadvantages.

In "Little Endian" form, assembly language instructions for picking up a 1, 2, 4, or longer byte number proceed in exactly the same way for all formats: first pick up the lowest order byte at offset 0. Also, because of the 1:1 relationship between address offset and byte number (offset 0 is byte 0), multiple precision math routines are correspondingly easy to write.

In "Big Endian" form, by having the high-order byte come first, you can always test whether the number is positive or negative by looking at the byte at offset zero. You don't have to know how long the number is, nor do you have to skip over any bytes to find the byte containing the sign information. The numbers are also stored in the order in which they are printed out,so binary to decimal routines are particularly efficient.

What does that Mean for Us?

用什么字节序意味着你任何时候再写数据到文件时,你必须知道这个文件是如何构建的。如果你写到一个图形文件中(如一个.BMP文件)在一个"Big Endian" 字节序的机器上,你必须先逆序字节顺序,否则标准的程序将无法读你的文件。
What endian order means is that any time numbers are written to a file, you have to know how the file is supposed to be constructed. If you write out a graphics file (such as a .BMP file) on a machine with "Big Endian" integers, you must first reverse the byte order, or a "standard" program to read your file won't work.

在windows上的.BMP格式,由于它是 "Little Endian" 结构, insists on the "Little Endian" format,你必须用这种方式实现你的BMP保存代码,不管你用的平台。

The Windows .BMP format, since it was developed on a "Little Endian" architecture, insists on the "Little Endian" format. You must write your Save_BMP code this way, regardless of the platform you are using.

Common file formats and their endian order are as follows:

  • Adobe Photoshop -- Big Endian
  • BMP (Windows and OS/2 Bitmaps) -- Little Endian
  • DXF (AutoCad) -- Variable
  • GIF -- Little Endian
  • IMG (GEM Raster) -- Big Endian
  • JPEG -- Big Endian
  • FLI (Autodesk Animator) -- Little Endian
  • MacPaint -- Big Endian
  • PCX (PC Paintbrush) -- Little Endian
  • PostScript -- Not Applicable (text!)
  • POV (Persistence of Vision ray-tracer) -- Not Applicable (text!)
  • QTM (Quicktime Movies) -- Little Endian (on a Mac!)
  • Microsoft RIFF (.WAV & .AVI) -- Both
  • Microsoft RTF (Rich Text Format) -- Little Endian
  • SGI (Silicon Graphics) -- Big Endian
  • Sun Raster -- Big Endian
  • TGA (Targa) -- Little Endian
  • TIFF -- Both, Endian identifier encoded into file
  • WPG (WordPerfect Graphics Metafile) -- Big Endian (on a PC!)
  • XWD (X Window Dump) -- Both, Endian identifier encoded into file

Correcting for the Non-Native Order
修改字节顺序

当你发现你需要另一种格式时,逆序字节是很容易的,一个简单的方法可以实现互相转换,这里有一个简单但不是很高效的版本:
It is pretty easy to reverse a multibyte integer if you find you need the other format. A single function can be used to switch from one to the other, in either direction. A simple and not very efficient version might look as follows: 

Function Reverse (N:LongInt) : LongInt ; Var B0, B1, B2, B3 : Byte ; Begin B0 := N Mod 256 ; N := N Div 256 ; B1 := N Mod 256 ; N := N Div 256 ; B2 := N Mod 256 ; N := N Div 256 ; B3 := N Mod 256 ; Reverse := (((B0 * 256 + B1) * 256 + B2) * 256 + B3) ; End ; A more efficient version that depends on the presence of hexadecimal numbers, bit masking operators AND, OR, and NOT, and shift operators SHL and SHR might look as follows: Function Reverse (N:LongInt) : LongInt ; Var B0, B1, B2, B3 : Byte ; Begin B0 := (N AND $000000FF) SHR 0 ; B1 := (N AND $0000FF00) SHR 8 ; B2 := (N AND $00FF0000) SHR 16 ; B3 := (N AND $FF000000) SHR 24 ; Reverse := (B0 SHL 24) OR (B1 SHL 16) OR (B2 SHL 8) OR (B3 SHL 0) ; End ; There are certainly more efficient methods, some of which are quite machine and platform dependent. Use what works best.

 



转自:http://www.cnblogs.com/me-sa/archive/2011/12/25/erlang0024.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值