我用 C 语言编写了一个快速排序的实现作为 Elixir NIF。我知道有一个 BIF,我这样做只是为了自学 NIF。
现在我的代码到目前为止可以工作,也就是说,我可以调用
MyQuicksort.my_quicksort([1,100,2])
并按预期返回 [1,2,100]
。然而,elixir 整数可以是任意大,如果我调用 MyQuicksort.my_quicksort([123, 67_845_734_623_721_230_492_834, 1])
,我会得到 ~c"get_int gone wrong"
。这是我自己的错误消息,但要点是 enif_get_long
对于大整数值不会成功。在 https://www.erlang.org/doc/man/erl_nif 上,所有用于整数类型的 enif_get_$TYPE
函数都有一些提示,例如“如果 term
超出类型范围,则返回 false”。
因此,我的问题是是否有办法在 NIF 函数内处理此类整数。 这是我用来将 Elixir 列表转换为 C 数组的代码。
static ERL_NIF_TERM my_quicksort(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
uint size;
if (!enif_get_list_length(env, argv[0], &size))
return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);
if (size > INT_MAX)
return enif_make_string(env, "list size too large", ERL_NIF_UTF8);
long n[size];
ERL_NIF_TERM head;
ERL_NIF_TERM old_tail = argv[0];
ERL_NIF_TERM new_tail;
for (int i = 0; i < size; i++) {
if (!enif_get_list_cell(env, old_tail, &head, &new_tail))
return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);
if (!enif_get_long(env, head, &n[i]))
return enif_make_string(env, "get_int gone wrong", ERL_NIF_UTF8);
old_tail = new_tail;
}
quicksort(n, 0, size - 1);
我知道为什么我的程序会像我所描述的那样运行。我觉得我只是缺少正确的
enif_get_$TYPE
函数来解构此类整数。
好吧,所以,我自己回答这个问题,到目前为止我发现的是比较两个
enif_compare
的 ERL_NIF_TERM
函数。
这意味着我只需将表示列表的
ERL_NIF_TERM
转换为包含其所有元素的数组即可排序。这是我在答案中列出的代码部分在我融入这个想法后的样子。
static ERL_NIF_TERM my_quicksort(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
uint size;
if (!enif_get_list_length(env, argv[0], &size))
return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);
if (size > INT_MAX)
return enif_make_string(env, "list size too large", ERL_NIF_UTF8);
ERL_NIF_TERM n[size];
ERL_NIF_TERM head;
ERL_NIF_TERM old_tail = argv[0];
ERL_NIF_TERM new_tail;
for (uint i = 0; i < size; i++) {
if (!enif_get_list_cell(env, old_tail, &n[i], &new_tail))
return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);
old_tail = new_tail;
}
quicksort(n, 0, size - 1);
return enif_make_list_from_array(env, n, size);
然后只需相应调整
quicksort
函数中使用的类型以及它使用的排序函数即可。
请注意,如果您忘记实际使用
enif_compare(x,y) > 0
来代替 x > y
,您不会收到错误,但仍然无法获得大数字所需的行为。
完成此操作后,我可以拨打电话
MyQuicksort.my_quicksort([
123,
97_845_734_623_721_230_492_834,
67_845_734_623_721_830_492_834,
111,
67_845_734_623_721_230_492_111,
9909
])
并实际取回排序后的列表。