ei
ei
C Library
ei
图书馆摘要
处理Erlang二进制术语格式的例程。
描述
图书馆ei
包含宏和函数来编码和解码Erlang二进制术语格式。
ei
允许您将二进制格式的原子,列表,数字和二进制文件转换为二进制格式。编写端口程序和驱动程序时这很有用。ei
使用给定的缓冲区,没有动态内存(ei_decode_fun()
除外),并且通常非常快。
ei
还处理C节点、C程序,这些程序与Erlang节点%28或其他C节点%29使用Erlang分发格式讨论Erlang分发。之间的区别ei
和erl_interface
那是ei
在发送和接收术语时直接使用二进制格式。它也是线程安全的,使用线程,一个进程可以处理多个C节点.。大erl_interface
图书馆建在ei
,但由于遗留原因,它不允许多个C节点。总的来说,ei
是执行C节点的首选方法。
解码和编码函数使用缓冲区和索引到缓冲区中,这将指向编码和解码的位置。索引被更新到在术语编码/解码后立即指向。不检查该术语是否适合缓冲区。如果编码超出缓冲区,程序就会崩溃。
所有函数都有两个参数:
buf
指向二进制数据所在的缓冲区的指针。
index
指向缓冲区的索引的指针。此参数随解码/编码术语的大小而递增。
这些数据因此在调用函数buf[*index]
时发生ei
。
所有编码函数都假定buf
和index
参数指向足以容纳数据的缓冲区。若要获取编码项的大小,而不对其进行编码,请传递NULL
而不是缓冲区指针。参数index
是递增的,但是没有编码。这就是进来的路ei
到“飞行前”术语编码。
还有使用动态缓冲区的编码函数。使用这些来编码数据通常更方便。所有的编码函数都有两个版本;第一个版本是ei_x
使用动态缓冲区。
如果成功,所有函数都会返回0,否则返回-1
(例如,如果一个术语不是预期的类型,或者要解码的数据是一个无效的Erlang术语)。
某些解码功能需要预先分配的缓冲区。此缓冲区必须足够大,对于非复合类型,ei_get_type()
函数返回所需的大小(请注意,对于字符串,需要额外的字节用于NULL
-terminator)。
数据类型
erlang_char_encoding
typedef enum {
ERLANG_ASCII = 1,
ERLANG_LATIN1 = 2,
ERLANG_UTF8 = 4
} erlang_char_encoding;
用于原子的字符编码。ERLANG_ASCII
代表7位ASCII码。Latin-1和UTF-8是7位ASCII的不同扩展名。所有7位ASCII字符都是有效的Latin-1和UTF-8字符。ASCII和Latin-1都代表每个字符一个字节。一个UTF-8字符可以由1-4个字节组成。请注意,这些常量是位标志,可以按位或组合。
输出
int ei_decode_atom(const char *buf, int *index, char *p)
从二进制格式解码原子。NULL
原子的终止名称被放置在p
。最多的MAXATOMLEN
字节可以放在缓冲区中。
int ei_decode_atom_as(const char *buf, int *index, char *p, int plen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result)
从二进制格式解码原子。NULL
原子的终止名称被放置在p
长度为plen
字节的缓冲区中。
想要的字符串编码由want指定。 二进制格式(Latin-1或UTF-8)中使用的原始编码可以从*获得。 结果字符串的编码(7位ASCII,Latin-1或UTF-8)可以从*结果中获得。 两者都是和结果可以是NULL。 如果want是像ERLANG_LATIN1 | ERLANG_UTF8那样的按位OR'd组合,或者如果*结果是纯7位ASCII(兼容Latin-1和UTF-8),则结果可能与预期不同。
如果原子对于缓冲区太长或者无法用编码想要表示,则此函数失败。
这个函数在Erlang / OTP R16中引入,作为支持UTF-8原子的第一步的一部分。
int ei_decode_bignum(const char *buf, int *index, mpz_t obj)
将二进制格式的整数解码为GMP mpz_t整数。 要使用此功能,必须配置和编译ei库以使用GMP库。
int ei_decode_binary(const char *buf, int *index, void *p, long *len)
从二进制格式解码二进制文件。参数len
设置为二进制文件的实际大小。注意,ei_decode_binary()
假设二进制文件有足够的空间。所需的大小可以通过ei_get_type()
。
int ei_decode_boolean(const char *buf, int *index, int *p)
从二进制格式解码布尔值。 布尔实际上是一个原子,真解码1和假解码0。
int ei_decode_char(const char *buf, int *index, char *p)
从二进制格式解码0-255之间的char
(8位)整数。由于历史原因,返回的整数是类型的char
。unsigned char
即使C编译器和系统可以定义char
为被签名,您的C代码也会将返回的值视为类型。
int ei_decode_double(const char *buf, int *index, double *p)
从二进制格式解码双精度(64位)浮点数。
int ei_decode_ei_term(const char* buf, int* index, ei_term* term)
解码任何术语,或者至少尝试。 如果buf中的*索引指向的术语适合术语联合,则将其解码,并设置术语 - >值中的适当字段,并且*索引增加术语大小。
该函数在成功解码时返回1,错误时返回-1,如果该术语看起来没问题,则返回0,但不适合术语结构。 如果返回1,则索引增加,并且项包含解码后的项。
该term
结构包含元组或列表的元素,二进制,字符串或原子的大小。它包含一个术语,如果它是以下任何一个术语:整数,浮点数,原子,pid,端口或参考。
int ei_decode_fun(const char *buf, int *index, erlang_fun *p)void free_fun(erlang_fun* f)
从二进制格式解码一个乐趣。 参数p是NULL或指向erlang_fun结构。 这是分配内存的唯一解码功能。 当不再需要erlang_fun时,它将被free_fun释放。 (这与有趣的环境的任意大小有关。)
int ei_decode_list_header(const char *buf, int *index, int *arity)
从二进制格式解码列表标题。 元素的数量返回arity。 元素+ 1元素跟随(最后一个是列表的尾部,通常是一个空列表)。 如果arity为0,则它是一个空列表。
请注意,如果列表完全由范围为0到255的整数组成,则列表将被编码为字符串。这个函数不会解码这些字符串,而是使用ei_decode_string()
。
int ei_decode_long(const char *buf, int *index, long *p)
从二进制格式解码长整数。如果代码是64位,则函数ei_decode_long()
类似于ei_decode_longlong()
...
int ei_decode_longlong(const char *buf, int *index, long long *p)
从二进制格式解码GCC long long
或Visual C ++ __int64
(64位)整数。该功能在VxWorks端口中缺失。
int ei_decode_map_header(const char *buf, int *index, int *arity)
从二进制格式解码地图标题。键值对的数量返回*arity
。键和值按照以下顺序排列:K1, V1, K2, V2, ..., Kn, Vn
。这使得arity*2
条款总数。如果arity
为零,则它是空的地图。正确编码的地图不具有重复的键。
int ei_decode_pid(const char *buf, int *index, erlang_pid *p)
从二进制格式解码进程标识符(pid)。
int ei_decode_port(const char *buf, int *index, erlang_port *p)
从二进制格式解码端口标识符。
int ei_decode_ref(const char *buf, int *index, erlang_ref *p)
从二进制格式解码引用。
int ei_decode_string(const char *buf, int *index, char *p)
从二进制格式解码字符串。Erlang中的字符串是0到255之间的整数列表。请注意,由于字符串只是一个列表,因此有时列表会被编码为字符串term_to_binary/1
,即使它不是有意的。
该字符串被复制到p
,并且必须分配足够的空间。返回的字符串被NULL
终止,所以您必须为内存需求添加一个额外的字节。
int ei_decode_term(const char *buf, int *index, void *t)
从二进制格式解码术语。 该术语作为ETERM *返回t,因此t实际上是ETERM **(请参阅erl_eterm)。 该术语稍后将被释放。
注意这个函数位于Erl_Interface
库中。
int ei_decode_trace(const char *buf, int *index, erlang_trace *p)
从二进制格式解码Erlang跟踪令牌。
int ei_decode_tuple_header(const char *buf, int *index, int *arity)
解码元组头,元素的数量返回arity
。元组元素在缓冲区中按顺序排列。
int ei_decode_ulong(const char *buf, int *index, unsigned long *p)
从二进制格式解码无符号长整数。如果代码是64位,则函数ei_decode_ulong()
类似于ei_decode_ulonglong()
...
int ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)
从二进制格式解码GCC无符号long long或Visual C ++无符号__int64(64位)整数。 该功能在VxWorks端口中缺失。
int ei_decode_version(const char *buf, int *index, int *version)
解码Erlang二进制术语格式的版本幻数。它必须是二进制术语中的第一个标记。
int ei_encode_atom(char *buf, int *index, const char *p)int ei_encode_atom_len(char *buf, int *index, const char *p, int len)int ei_x_encode_atom(ei_x_buff* x, const char *p)int ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)
以二进制格式编码原子。参数p
是Latin-1编码中原子的名称。只有最多MAXATOMLEN-1
字节被编码。该名称将被NULL
终止,除了该ei_x_encode_atom_len()
功能。
int ei_encode_atom_as(char *buf, int *index, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)int ei_encode_atom_len_as(char *buf, int *index, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)int ei_x_encode_atom_as(ei_x_buff* x, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)int ei_x_encode_atom_len_as(ei_x_buff* x, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)
以二进制格式编码原子。Parameter p
是具有字符编码的原子的名称from_enc
(ASCII,Latin-1或UTF-8)。该名称必须被NULL
终止,或者len
必须使用带参数的函数变体。
如果p
在编码中不是有效的字符串,则编码from_enc
将失败。
论据to_enc
被忽略。从Erlang / OTP 20开始,编码总是以UTF-8格式完成,这种格式可以像Erlang / OTP R16一样陈旧。
int ei_encode_bignum(char *buf, int *index, mpz_t obj)int ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)
将GMP mpz_t
整数编码为二进制格式。要使用此功能,ei
必须对库进行配置和编译以使用GMP库。
int ei_encode_binary(char *buf, int *index, const void *p, long len)int ei_x_encode_binary(ei_x_buff* x, const void *p, long len)
以二进制格式编码二进制文件。的数据是在p
,的len
字节长度。
int ei_encode_boolean(char *buf, int *index, int p)int ei_x_encode_boolean(ei_x_buff* x, int p)
如果p不为零,则将布尔值编码为原子真;如果p为零,则将其编码为假。
int ei_encode_char(char *buf, int *index, char p)int ei_x_encode_char(ei_x_buff* x, char p)
以二进制格式的0-255之间的整数对char(8位)进行编码。 由于历史原因,整数参数是char类型。 即使C编译器和系统可能定义要被签名的char,你的C代码也会将指定的参数视为unsigned char类型。
int ei_encode_double(char *buf, int *index, double p)int ei_x_encode_double(ei_x_buff* x, double p)
以二进制格式编码双精度(64位)浮点数。
如果浮点数不是有限的,则返回-1
。
int ei_encode_empty_list(char* buf, int* index)int ei_x_encode_empty_list(ei_x_buff* x)
对空列表进行编码。它经常在列表的尾部使用。
int ei_encode_fun(char *buf, int *index, const erlang_fun *p)int ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)
以二进制格式编码一个乐趣。 参数p指向erlang_fun结构。 erlang_fun不会自动释放,如果编码后不需要fun,则会调用free_fun。
int ei_encode_list_header(char *buf, int *index, int arity)int ei_x_encode_list_header(ei_x_buff* x, int arity)
使用指定的元素编码列表标题。接下来的arity+1
术语是元素(实际上是它的arity
cons单元)和列表的尾部。列表和元组是递归编码的,所以列表可以包含另一个列表或元组。
例如,要对列表[c, d, [e | f]]
进行编码:
ei_encode_list_header(buf, &i, 3
ei_encode_atom(buf, &i, "c"
ei_encode_atom(buf, &i, "d"
ei_encode_list_header(buf, &i, 1
ei_encode_atom(buf, &i, "e"
ei_encode_atom(buf, &i, "f"
ei_encode_empty_list(buf, &i
注
似乎没有办法在事先不知道元素数量的情况下创建列表。但确实有办法。注意列表[a, b, c]
可以写成[a | [b | [c]]]
。使用这个,列表可以写成conses。
对列表进行编码,而事先不知道其重要性:
while (something()) {
ei_x_encode_list_header(&x, 1
ei_x_encode_ulong(&x, i /* just an example */
}
ei_x_encode_empty_list(&x
int ei_encode_long(char *buf, int *index, long p)int ei_x_encode_long(ei_x_buff* x, long p)
以二进制格式编码长整数。如果代码是64位,则函数ei_encode_long()
类似于ei_encode_longlong()
...
int ei_encode_longlong(char *buf, int *index, long long p)int ei_x_encode_longlong(ei_x_buff* x, long long p)
以二进制格式编码GCC long long
或Visual C ++ __int64
(64位)整数。该功能在VxWorks端口中缺失。
int ei_encode_map_header(char *buf, int *index, int arity)int ei_x_encode_map_header(ei_x_buff* x, int arity)
使用指定的arity编码地图标题。 下一个编码的* 2项将是按以下顺序编码的映射的键和值:K1,V1,K2,V2,...,Kn,Vn。
例如,要编码map#{a => "Apple", b => "Banana"}:
ei_x_encode_map_header(&x, 2
ei_x_encode_atom(&x, "a"
ei_x_encode_string(&x, "Apple"
ei_x_encode_atom(&x, "b"
ei_x_encode_string(&x, "Banana"
正确编码的映射不能有重复的键。
int ei_encode_pid(char *buf, int *index, const erlang_pid *p)int ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)
以二进制格式编码Erlang进程标识符(p
id)。参数p
指向一个erlang_pid
结构(应该在之前获得ei_decode_pid()
)。
int ei_encode_port(char *buf, int *index, const erlang_port *p)int ei_x_encode_port(ei_x_buff* x, const erlang_port *p)
以二进制格式编码Erlang端口。参数p
指向一个erlang_port
结构(应该在之前获得ei_decode_port()
)。
int ei_encode_ref(char *buf, int *index, const erlang_ref *p)int ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)
以二进制格式编码Erlang参考。参数p
指向一个erlang_ref
结构(应该在之前获得ei_decode_ref()
)。
int ei_encode_string(char *buf, int *index, const char *p)int ei_encode_string_len(char *buf, int *index, const char *p, int len)int ei_x_encode_string(ei_x_buff* x, const char *p)int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)
以二进制格式编码字符串。(Erlang中的字符串是一个列表,但被编码为二进制格式的字符数组。)该字符串将被NULL
终止,但该ei_x_encode_string_len()
函数除外。
int ei_encode_term(char *buf, int *index, void *t)int ei_x_encode_term(ei_x_buff* x, void *t)
编码一个ETERM
,从中获得erl_interface
。参数t
实际上是一个ETERM
指针。此功能不释放ETERM
。
int ei_encode_trace(char *buf, int *index, const erlang_trace *p)int ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)
以二进制格式编码Erlang跟踪令牌。参数p
指向一个erlang_trace
结构(应该在之前获得ei_decode_trace()
)。
int ei_encode_tuple_header(char *buf, int *index, int arity)int ei_x_encode_tuple_header(ei_x_buff* x, int arity)
编码具有指定元素的元组标题。接下来arity
编码的术语将是元组的元素。元组和列表是递归编码的,所以元组可以包含另一个元组或列表。
例如,对元组进行编码。{a, {b, {}}}
*
ei_encode_tuple_header(buf, &i, 2
ei_encode_atom(buf, &i, "a"
ei_encode_tuple_header(buf, &i, 2
ei_encode_atom(buf, &i, "b"
ei_encode_tuple_header(buf, &i, 0
int ei_encode_ulong(char *buf, int *index, unsigned long p)int ei_x_encode_ulong(ei_x_buff* x, unsigned long p)
以二进制格式对无符号长整数进行编码。如果代码是64位,则函数ei_encode_ulong()
类似于ei_encode_ulonglong()
...
int ei_encode_ulonglong(char *buf, int *index, unsigned long long p)int ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)
以二进制格式编码GCC unsigned long long
或Visual C ++ unsigned __int64
(64位)整数。该功能在VxWorks端口中缺失。
int ei_encode_version(char *buf, int *index)int ei_x_encode_version(ei_x_buff* x)
编码二进制格式的版本数。必须是二进制术语中的第一个标记。
int ei_get_type(const char *buf, const int *index, int *type, int *size)
返回编码术语大小的类型和大小。 对于字符串和原子,大小是不包括终止NULL的字符数。 对于二进制文件,大小是字节数。 对于列表和元组,大小是对象的arity。 对于其他类型,大小为0.在所有情况下,索引保持不变。
int ei_print_term(FILE* fp, const char* buf, int* index)int ei_s_print_term(char** s, const char* buf, int* index)
以明文形式将术语打印到指定的文件fp
或指向的缓冲区s
。它试图类似于在Erlang s
hell中打印的术语。
在ei_s_print_term()
,参数s
是指向一个动态(malloc)分配的BUFSIZ
字节串或一个NULL
指针。*s
如果结果多于BUFSIZ
字符,则可以通过此函数重新分配字符串(并可进行更新)。返回的字符串被NULL
终止。
返回值是写入文件或字符串的字符数,如果buf [index]不包含有效的项,则返回-1。 不幸的是,fp上的I / O错误没有被检查。
参数index
被更新,也就是说,这个函数可以被看作是一个解码函数,它将一个术语解码为一个可读的格式。
void ei_set_compat_rel(release_number)
类型
默认情况下,ei库只能保证与ei库本身的相同版本中的其他Erlang / OTP组件兼容。 例如,来自Erlang / OTP R10的ei默认与Erlang / OTP R9的Erlang仿真器不兼容。
调用ei_set_compat_rel(release_number)
将ei
库设置为发布的兼容模式release_number
。有效范围release_number
是[7, current release]
。这使得与早期版本的Erlang / OTP组件进行通信成为可能。
注
如果这个函数被调用,它只能被调用一次,并且必须在ei
库中的任何其他函数被调用之前被调用。
警告
如果不小心使用此功能,您可能会遇到麻烦。始终确保所有通信组件要么来自同一个Erlang/OTP版本,要么来自X版和Y版,其中Y版的所有组件都处于X版的兼容模式。
int ei_skip_term(const char* buf, int* index)
跳过指定缓冲区中的术语;递归跳过列表和元组的元素,从而跳过整个术语。这是获取Erlang项大小的一种方法。
buf
是缓冲区。
index
更新为在缓冲区中的术语后面指向。
注
当您想要持有任意的术语时,这可能很有用:跳过它们并将二进制术语数据复制到某个缓冲区。
成功时返回 0,否则返回-1
。
int ei_x_append(ei_x_buff* x, const ei_x_buff* x2)int ei_x_append_buf(ei_x_buff* x, const char* buf, int len)
在缓冲区末尾追加数据。x
...
int ei_x_format(ei_x_buff* x, const char* fmt, ...)int ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )
将一个词作为字符串格式化为一个缓冲区。 用于Erlang条款的sprintf。 fmt包含一个格式字符串,带有像〜d这样的参数,用于从变量中插入术语。 支持以下格式(给出C类型):
~a An atom, char*
~c A character, char
~s A string, char*
~i An integer, int
~l A long integer, long int
~u A unsigned long integer, unsigned long int
~f A float, float
~d A double float, double float
~p An Erlang pid, erlang_pid*
例如,要用以下内容对元组进行编码:
ei_x_format("{~a,~i,~d}", "numbers", 12, 3.14159)
encodes the tuple {numbers,12,3.14159}
ei_x_format_wo_ver()
格式设置为缓冲区,而不使用初始版本字节。
int ei_x_free(ei_x_buff* x)
解放ei_x_buff
缓冲器。缓冲区使用的内存返回到操作系统。
int ei_x_new(ei_x_buff* x)int ei_x_new_with_version(ei_x_buff* x)
分配一个新的ei_x_buff
缓冲区。由参数指向的结构的字段x
被填充,并且分配默认缓冲区。ei_x_new_with_version()
还会放入一个初始版本字节,该字节以二进制格式使用(所以ei_x_encode_version()
不需要)。
调试信息
在模拟器似乎没有接收到您发送的条件时检查哪些内容的一些提示:
- 请小心使用版本标题,且
ei_x_new_with_version()
在适当时使用。
- 打开Erlang节点上的分布跟踪。
- 检查结果代码
ei_decode_-calls
...
另见
erl_eterm