查看源代码 ei

用于处理 Erlang 二进制项格式的例程。

描述

ei 包含用于编码和解码 Erlang 二进制项格式的宏和函数。

ei 允许您将原子、列表、数字和二进制数据转换为二进制格式,以及从二进制格式转换。这在编写端口程序和驱动程序时很有用。ei 使用给定的缓冲区,没有动态内存(除了 ei_decode_fun()),并且通常速度很快。

ei 还处理 C 节点,即使用 Erlang 分布格式与 Erlang 节点(或其他 C 节点)进行 Erlang 分布通信的 C 程序。ei 库是线程安全的,并且使用线程,一个进程可以处理多个 C 节点。

解码和编码函数使用缓冲区和缓冲区中的索引,该索引指向编码和解码的位置。索引会更新为指向编码/解码的项之后的位置。不会检查该项是否适合缓冲区。如果编码超出缓冲区,程序可能会崩溃。

所有函数都接受两个参数

  • buf 是指向二进制数据所在的缓冲区或将要写入的缓冲区的指针。
  • index 是指向缓冲区中索引的指针。此参数会随着解码/编码的项的大小而增加。

因此,当调用 ei 函数时,数据位于 buf[*index]

所有编码函数都假定 bufindex 参数指向足够大的缓冲区以容纳数据。请注意,二进制项格式使用可变长度编码,因此不同的值可能需要不同的空间大小。例如,较小的整数值可能比更大的整数值更紧凑。要在不编码的情况下获取编码项的大小,请传递 NULL 而不是缓冲区指针。参数 index 会递增,但不会编码任何内容。这是在 ei 中“预检”项编码的方法。

还有一些使用动态缓冲区的编码函数。通常,使用这些函数来编码数据会更方便。所有编码函数都有两个版本;以 ei_x_ 开头的那些使用 ei_x_buff 类型的动态缓冲区。

如果成功,所有函数都返回 0,否则返回 -1(例如,如果项不是预期类型,或者要解码的数据是无效的 Erlang 项)。

某些解码函数需要预先分配的缓冲区。必须分配足够大的缓冲区,对于非复合类型,ei_get_type() 函数会返回所需的大小(请注意,对于字符串,需要额外的字节用于 NULL 终止符)。

数据类型

  • ei_term

    typedef struct {
        char ei_type;
        int arity;
        int size;
        union {
      long i_val;
      double d_val;
      char atom_name[MAXATOMLEN_UTF8];
      erlang_pid pid;
      erlang_port port;
      erlang_ref ref;
        } value;
    } ei_term;

    ei_decode_ei_term() 写入的结构。ei_type 字段是项的类型,它等于 ei_get_type()*type 设置为的值。

  • ei_x_buff - 动态调整大小的缓冲区。它是一个 struct,其中包含用户感兴趣的两个字段

    • char *buff - 指向动态分配缓冲区的指针。

    • int index - 指向要写入的下一个字节的偏移量,也等于当前写入的字节数。

    ei_x_buff 通过调用 ei_x_new()ei_x_new_with_version() 进行初始化。通过调用 ei_x_free() 释放初始化的 ei_x_buff 使用的内存。

  • 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 个字节组成。请注意,这些常量是位标志,可以与按位或组合。

  • erlang_fun - 表示 Erlang 函数的不透明数据类型。

  • erlang_pid - 表示 Erlang 进程标识符的不透明数据类型。

  • erlang_port - 表示 Erlang 端口标识符的不透明数据类型。

  • erlang_ref - 表示 Erlang 引用的不透明数据类型。

  • erlang_trace - 表示 Erlang 顺序跟踪令牌的不透明数据类型。

ei_cmp_pids()

int ei_cmp_pids(erlang_pid *a, erlang_pid *b);

比较两个进程标识符。比较方式与 Erlang 相同。

如果 ab 相等,则返回 0。如果 a 的比较结果小于 b,则返回小于 0 的值。如果 a 的比较结果大于 b,则返回大于 0 的值。

自 OTP 23.0 起可用

ei_cmp_ports()

int ei_cmp_ports(erlang_port *a, erlang_port *b);

比较两个端口标识符。比较方式与 Erlang 相同。

如果 ab 相等,则返回 0。如果 a 的比较结果小于 b,则返回小于 0 的值。如果 a 的比较结果大于 b,则返回大于 0 的值。

自 OTP 23.0 起可用

ei_cmp_refs()

int ei_cmp_refs(erlang_ref *a, erlang_ref *b);

比较两个引用。比较方式与 Erlang 相同。

如果 ab 相等,则返回 0。如果 a 的比较结果小于 b,则返回小于 0 的值。如果 a 的比较结果大于 b,则返回大于 0 的值。

自 OTP 23.0 起可用

ei_decode_atom()

int ei_decode_atom(const char *buf, int *index, char *p);

从二进制格式解码原子。原子的以 NULL 结尾的名称放置在 p 处。缓冲区中最多可以放置 MAXATOMLEN 个字节。

ei_decode_atom_as()

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)可以从 *was 获取。结果字符串的编码(7 位 ASCII、Latin-1 或 UTF-8)可以从 *result 获取。wasresult 都可以为 NULL。如果 want 是按位或组合(如 ERLANG_LATIN1|ERLANG_UTF8)或者如果 *result 结果是纯 7 位 ASCII(与 Latin-1 和 UTF-8 兼容),则 *result 可能与 want 不同。

如果原子对于缓冲区来说太长或无法用编码 want 表示,则此函数将失败。

此函数在 Erlang/OTP R16 中引入,作为支持 UTF-8 原子的第一步。

自 OTP R16B 起可用

ei_decode_bignum()

int ei_decode_bignum(const char *buf, int *index, mpz_t obj);

将二进制格式的整数解码为 GMP mpz_t 整数。要使用此函数,必须配置和编译 ei 库才能使用 GMP 库。

ei_decode_binary()

int ei_decode_binary(const char *buf, int *index, void *p, long *len);

从二进制格式解码二进制数据。参数 len 设置为二进制数据的实际大小。请注意,ei_decode_binary() 假定有足够的空间用于二进制数据。所需的大小可以通过 ei_get_type() 获取。

ei_decode_bitstring()

int ei_decode_bitstring(const char *buf, int *index, const char **pp,
  unsigned int *bitoffsp, size_t *nbitsp);

从二进制格式解码位串。

  • pp - NULL*pp 返回指向位串第一个字节的指针。只要 buf 指向的缓冲区是可读的且未写入,返回的位串就是可读的。

  • bitoffsp - NULL*bitoffsp 返回 *pp 指向的第一个字节中未使用的位数。*bitoffsp 的值介于 0 和 7 之间。第一个字节中未使用的位是最高有效位。

  • nbitsp - NULL*nbitsp 返回位串的长度(以为单位)。

如果它是位串项,则返回 0

*pp 指向的字节数是位串的一部分,为 (*bitoffsp + *nbitsp + 7)/8。如果 (*bitoffsp + *bitsp)%8 > 0,则仅使用最后一个字节的 (*bitoffsp + *bitsp)%8 位。最后一个字节中未使用的位是最低有效位。

第一个字节和最后一个字节中未使用的位的值是未定义的,不能依赖它。

位数可以被 8 整除,这意味着可以通过 ei_decode_binary 解码的二进制数据也可以通过 ei_decode_bitstring 解码。

自 OTP 22.0 起可用

ei_decode_boolean()

int ei_decode_boolean(const char *buf, int *index, int *p);

从二进制格式解码布尔值。布尔值实际上是一个原子,true 解码为 1,false 解码为 0。

ei_decode_char()

int ei_decode_char(const char *buf, int *index, char *p);

从二进制格式解码 0-255 之间的字符 (8 位) 整数。由于历史原因,返回的整数类型为 char。即使 C 编译器和系统可以将 char 定义为有符号的,您的 C 代码也应将返回的值视为 unsigned char 类型。

ei_decode_double()

int ei_decode_double(const char *buf, int *index, double *p);

从二进制格式解码双精度 (64 位) 浮点数。

ei_decode_ei_term()

int ei_decode_ei_term(const char* buf, int* index, ei_term* term);

解码任何项,或者至少尝试解码。如果 buf*index 指向的项适合 term 联合,则会解码它,并且设置 term->value 中的相应字段,并且 *index 会递增项的大小。

如果成功解码,该函数返回 1;如果发生错误,则返回 -1;如果项看起来没问题,但与 term 结构不匹配,则返回 0。如果返回 1,则 index 会递增,并且 term 包含解码的项。

term 结构包含元组或列表的元数,以及二进制数据、字符串或原子的大小。如果它是以下任何一种类型,则包含一个项:整数、浮点数、原子、PID、端口或引用。

ei_decode_fun()

free_fun()

int ei_decode_fun(const char *buf, int *index, erlang_fun *p);
void free_fun(erlang_fun* f);

从二进制格式解码一个 fun。参数 p 必须为 NULL 或指向一个 erlang_fun 结构。这是唯一一个分配内存的解码函数。当不再需要 erlang_fun 时,应使用 free_fun 释放它。(这与 fun 的环境的任意大小有关。)

ei_decode_iodata()

int ei_decode_iodata(const char *buf, int *index, int *size, char *outbuf);

解码 iodata() 类型的项。 iodata/0 项将被展平并写入由 outbuf 参数指向的缓冲区。 iodata 的字节大小被写入由 size 参数指向的整数变量中。sizeoutbuf 都可以设置为 NULL。无论 sizeoutbuf 参数的状态如何,由 index 参数指向的整数都会被更新,以引用 iodata/0 项之后的项。

请注意,如果将非 NULL 值作为 outbuf 传递,则由 outbuf 参数指向的缓冲区必须足够大。通常需要调用 ei_decode_iodata() 两次。第一次使用非 NULLsize 参数和 NULLoutbuf 参数,以确定所需的缓冲区大小,然后再次调用以执行实际解码。请注意,由 index 指向的整数也会通过确定大小的调用进行更新,因此在进行实际解码的第二次调用之前,需要重置它。

成功时返回 0,失败时返回 -1。失败可能是由于项的编码无效或由于项不是 iodata/0 类型。如果失败,由 index 参数指向的整数将更新为引用检测到失败的子项。

自 OTP 23.0 起可用

ei_decode_list_header()

int ei_decode_list_header(const char *buf, int *index, int *arity);

从二进制格式解码列表头。元素的数量在 arity 中返回。arity+1 个元素紧随其后(最后一个是列表的尾部,通常是空列表)。如果 arity0,则表示空列表。

请注意,如果列表完全由 0..255 范围内的整数组成,则会将其编码为字符串。此函数不解码此类字符串,请改用 ei_decode_string()

ei_decode_long()

int ei_decode_long(const char *buf, int *index, long *p);

从二进制格式解码一个长整数。如果代码是 64 位,则函数 ei_decode_long()ei_decode_longlong() 相同。

ei_decode_longlong()

int ei_decode_longlong(const char *buf, int *index, long long *p);

从二进制格式解码一个 GCC long long 或 Visual C++ __int64 (64 位) 整数。

ei_decode_map_header()

int ei_decode_map_header(const char *buf, int *index, int *arity);

从二进制格式解码一个映射头。键值对的数量在 *arity 中返回。键和值按以下顺序排列:K1, V1, K2, V2, ..., Kn, Vn。这总共有 arity*2 个项。如果 arity 为零,则表示空映射。正确编码的映射没有重复的键。

自 OTP 17.0 起可用

ei_decode_pid()

int ei_decode_pid(const char *buf, int *index, erlang_pid *p);

从二进制格式解码一个进程标识符 (pid)。

ei_decode_port()

int ei_decode_port(const char *buf, int *index, erlang_port *p);

从二进制格式解码一个端口标识符。

ei_decode_ref()

int ei_decode_ref(const char *buf, int *index, erlang_ref *p);

从二进制格式解码一个引用。

ei_decode_string()

int ei_decode_string(const char *buf, int *index, char *p);

从二进制格式解码一个字符串。Erlang 中的字符串是介于 0 和 255 之间的整数列表。请注意,由于字符串只是一个列表,有时列表会被 term_to_binary/1 编码为字符串,即使它并非本意。

字符串被复制到 p,并且必须分配足够的空间。返回的字符串以 NULL 结尾,因此您必须为内存需求添加一个额外的字节。

ei_decode_trace()

int ei_decode_trace(const char *buf, int *index, erlang_trace *p);

从二进制格式解码一个 Erlang 跟踪标记。

ei_decode_tuple_header()

int ei_decode_tuple_header(const char *buf, int *index, int *arity);

解码一个元组头,元素的数量在 arity 中返回。元组元素按顺序在缓冲区中排列。

ei_decode_ulong()

int ei_decode_ulong(const char *buf, int *index, unsigned long *p);

从二进制格式解码一个无符号长整数。如果代码是 64 位,则函数 ei_decode_ulong()ei_decode_ulonglong() 相同。

ei_decode_ulonglong()

int ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p);

从二进制格式解码一个 GCC unsigned long long 或 Visual C++ unsigned __int64 (64 位) 整数。

ei_decode_version()

int ei_decode_version(const char *buf, int *index, int *version);

解码 Erlang 二进制项格式的版本魔数。它必须是二进制项中的第一个标记。

ei_encode_atom()

ei_encode_atom_len()

ei_x_encode_atom()

ei_x_encode_atom_len()

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() 函数除外。

ei_encode_atom_as()

自 OTP R16B 起可用

ei_encode_atom_len_as()

自 OTP R16B 起可用

ei_x_encode_atom_as()

自 OTP R16B 起可用

ei_x_encode_atom_len_as()

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);

以二进制格式编码一个原子。参数 p 是具有字符编码 from_enc(ASCII、Latin-1 或 UTF-8)的原子名称。名称必须以 NULL 结尾,或者必须使用带有 len 参数的函数变体。

如果 p 不是 from_enc 编码中的有效字符串,则编码失败。

参数 to_enc 被忽略。从 Erlang/OTP 20 开始,编码始终以 UTF-8 进行,这对于 Erlang/OTP R16 一样旧的节点都是可读的。

自 OTP R16B 起可用

ei_encode_bignum()

ei_x_encode_bignum()

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 库。

ei_encode_binary()

ei_x_encode_binary()

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 字节。

ei_encode_bitstring()

自 OTP 22.0 起可用

ei_x_encode_bitstring()

int ei_encode_bitstring(char *buf, int *index, const char *p, size_t bitoffs, size_t nbits);
int ei_x_encode_bitstring(ei_x_buff* x, const char *p, size_t bitoffs, size_t nbits);

以二进制格式编码一个位串。

数据位于 p。位串的长度为 nbits 位。 p 处数据的前 bitoffs 位未使用。位串的第一字节是 p[bitoffs/8]。第一个字节 p[bitoffs/8]bitoffs%8 最高有效位未使用。

位串的一部分的字节数为 (bitoffs + nbits + 7)/8。如果 (bitoffs + nbits)%8 > 0,则仅使用最后一个字节的 (bitoffs + nbits)%8 位。最后一个字节中未使用的位是最低有效位。

未使用的位的值将被忽略,无需清除。

自 OTP 22.0 起可用

ei_encode_boolean()

ei_x_encode_boolean()

int ei_encode_boolean(char *buf, int *index, int p);
int ei_x_encode_boolean(ei_x_buff* x, int p);

如果 p 不为零,则将布尔值编码为原子 true,如果 p 为零,则编码为 false

ei_encode_char()

ei_x_encode_char()

int ei_encode_char(char *buf, int *index, char p);
int ei_x_encode_char(ei_x_buff* x, char p);

以二进制格式将字符(8 位)编码为 0-255 之间的整数。出于历史原因,整数参数的类型为 char。即使 C 编译器和系统可能将 char 定义为有符号的,您的 C 代码也应将指定的参数视为 unsigned char 类型。

ei_encode_double()

ei_x_encode_double()

int ei_encode_double(char *buf, int *index, double p);
int ei_x_encode_double(ei_x_buff* x, double p);

以二进制格式编码双精度(64 位)浮点数。

如果浮点数不是有限数,则返回 -1

ei_encode_empty_list()

ei_x_encode_empty_list()

int ei_encode_empty_list(char* buf, int* index);
int ei_x_encode_empty_list(ei_x_buff* x);

编码一个空列表。它通常用在列表的末尾。

ei_encode_fun()

ei_x_encode_fun()

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);

以二进制格式编码一个 fun。参数 p 指向一个 erlang_fun 结构。 erlang_fun 不会自动释放,如果编码后不再需要该 fun,则需要调用 free_fun

ei_encode_list_header()

ei_x_encode_list_header()

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);

ei_encode_long()

ei_x_encode_long()

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() 相同。

ei_encode_longlong()

ei_x_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 位) 整数。

ei_encode_map_header()

自 OTP 17.0 起可用

ei_x_encode_map_header()

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

例如,要编码映射 #{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");

正确编码的映射不能有重复的键。

自 OTP 17.0 起可用

ei_encode_pid()

ei_x_encode_pid()

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 进程标识符 (pid)。参数 p 指向一个 erlang_pid 结构,该结构应该先前通过 ei_decode_pid()ei_self() 获取,或者通过 ei_make_pid() 创建。

ei_encode_port()

ei_x_encode_port()

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() 获取。

ei_encode_ref()

ei_x_encode_ref()

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() 获取,或者通过 ei_make_ref() 创建。

ei_encode_string()

ei_encode_string_len()

ei_x_encode_string()

ei_x_encode_string_len()

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() 函数之外。

ei_encode_trace()

ei_x_encode_trace()

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() 获取。

ei_encode_tuple_header()

ei_x_encode_tuple_header()

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);

ei_encode_ulong()

ei_x_encode_ulong()

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() 相同。

ei_encode_ulonglong()

ei_x_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 位) 整数。

ei_encode_version()

ei_x_encode_version()

int ei_encode_version(char *buf, int *index);
int ei_x_encode_version(ei_x_buff* x);

编码二进制格式的版本魔数。必须是二进制项中的第一个标记。

ei_get_type()

int ei_get_type(const char *buf, const int *index, int *type, int *size);

返回编码项的类型,存储在 *type 中,大小存储在 *size 中。对于字符串和原子,大小是不包括终止 NULL 的字符数。对于二进制文件和位串, *size 是字节数。对于列表、元组和映射, *size 是对象的元数。对于大整数, *size 是大整数绝对值的字节数。对于其他类型, *size 是 0。在所有情况下, index 保持不变。

目前, *type 是以下之一

如果不关心数据,也可以通过使用 ei_skip_term() 跳过一个项,而不是解码它。

ei_init()

int ei_init(void);

初始化 ei 库。在调用 ei 库中的任何其他功能之前,应该调用此函数一次(且仅一次)。

成功时返回零。失败时返回 posix 错误代码。

自 OTP 21.3 起可用

ei_print_term()

ei_s_print_term()

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 shell 中的项打印。

ei_s_print_term() 中,参数 s 指向一个动态(malloc)分配的 BUFSIZ 字节的字符串或一个 NULL 指针。如果结果超过 BUFSIZ 个字符,此函数可以重新分配字符串(并且可以更新 *s)。返回的字符串以 NULL 结尾。

返回值是写入文件或字符串的字符数,如果 buf[index] 不包含有效的项,则返回 -1。遗憾的是,不会检查 fp 上的 I/O 错误。

参数 index 会被更新,也就是说,这个函数可以被视为一个解码函数,将一个项解码成人类可读的格式。

ei_set_compat_rel()

void ei_set_compat_rel(unsigned release_number);

通常,ei 库保证与比 ei 库本身旧或新 2 个主要版本的其他 Erlang/OTP 组件兼容。

有时,为了使新功能(甚至错误修复)成为可能,必须对上述规则进行例外处理。调用 ei_set_compat_rel(release_number)ei 库设置为 OTP 版本 release_number 的兼容模式。

目前,release_number 的唯一有用值是 21。只有当从连接的节点接收到 *位字符串* 或 *导出函数* 时,这才会起作用并产生影响。在 OTP 22 之前,ei 不支持位字符串和导出函数。当从模拟器发送到 ei 时,它们改为使用未记录的回退元组格式进行编码。

  • 位字符串 - 项 <<42, 1:1>> 被编码为 {<<42, 128>>, 1}。元组的第一个元素是一个二进制数据,第二个元素表示最后字节中有多少位是位字符串的一部分。在本例中,只有最后一个字节 (128) 的最高有效位是位字符串的一部分。

  • 导出函数 - 项 fun lists:map/2 被编码为 {lists,map}。一个包含模块、函数和缺少元数的元组。

如果 *没有* 调用 ei_set_compat_rel(21),则连接的模拟器将发送正确编码的位字符串和导出函数。必须使用函数 ei_decode_bitstringei_decode_fun 来解码这些项。调用 ei_set_compat_rel(21) 应该只作为一种解决方法,以保持旧的实现继续工作,该实现期望接收位字符串和/或导出函数的未记录的元组格式。

注意

如果调用此函数,则只能调用一次,并且必须在调用 ei 库中的任何其他函数之前调用。

ei_skip_term()

int ei_skip_term(const char* buf, int* index);

跳过指定缓冲区中的一个项;递归地跳过列表和元组的元素,以便跳过一个完整的项。这是获取 Erlang 项大小的一种方法。

buf 是缓冲区。

index 会被更新,以指向缓冲区中该项之后的位置。

注意

当您想保存任意项时,这很有用:跳过它们并将二进制项数据复制到某个缓冲区。

成功时返回 0,否则返回 -1

ei_x_append()

ei_x_append_buf()

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 的末尾。

ei_x_format()

ei_x_format_wo_ver()

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() 将格式化到缓冲区中,而不包含初始版本字节。

更改

自 OTP 26.2 起,可以使用类似于 "#{k1 => v1, k2 => v2}" 的语法对映射进行编码。

ei_x_free()

int ei_x_free(ei_x_buff* x);

释放 x 引用的缓冲区的动态分配内容。释放后,buff 字段设置为 NULL

ei_x_new()

ei_x_new_with_version()

int ei_x_new(ei_x_buff* x);
int ei_x_new_with_version(ei_x_buff* x);

初始化 x 引用的动态可实现缓冲区。填充参数 x 指向的结构的字段,并分配一个默认缓冲区。ei_x_new_with_version() 还放置一个初始版本字节,该字节在二进制格式中使用(因此不需要 ei_x_encode_version()。)

调试信息

关于当模拟器似乎没有接收到您发送的项时,应检查的一些提示

  • 请注意版本标头,在适当的时候使用 ei_x_new_with_version()
  • 在 Erlang 节点上启用分布式跟踪。
  • 检查 ei_decode_-calls 的结果代码。