前言:本人不是C/C++程序员,只是为了了解erlang的内建函数,才重新捡起了C看了下,如果有不正确的地方,或者更好的处理方法,请留言指正!
1. 初始化
ERL_NIF_TERM hello(ErlNifEnv* env, int argCount, const ERL_NIF_TERM argv[]){
}
ERL_NIF_TERM change(ErlNifEnv* env, int argCount, const ERL_NIF_TERM argv[]){
}
static ErlNifFunc nif_funcs[] = {
{ "erl_change", 4, change },
{ "erl_hello",2, hello },
};
ERL_NIF_INIT(vsdll, nif_funcs, NULL, NULL, NULL, NULL);
ERL_NIF_INIT的第一个参数规定了erlang模块的名字.例如,我们要在test.erl中加载这个NIF,那么此参数就填入test.
第二个参数是该库中所有已实现的NIF的函数描述符的静态数组。说的直白点,该参数配置了这个NIF可以调用的方法,例如上面的代码就有两个可以调用的方法:erl_change/4,erl_hello/2.
此项配置需要和Erlang模块配合,test.erl模块中导出erl_change/4方法,C语言中实现change/3函数,该函数有三个参数(ErlNifEnv,参数个数,参数列表).
后面4个参数依次为&load, &reload, &upgrade, &unload,测试时直接配置为NULL即可.
2. int类型
//int类型比较简单,直接获取设置即可
if (enif_is_number(env, arg))//int
{
//从输入数据中获取int值
ErlNifSInt64 erlInt;
enif_get_int64(env, arg, &erlInt);
//将int值回写到erlang
int int1 = 99999;
enif_make_int64(env, int1);
}
3. binary类型
if (enif_is_binary(env, arg))//binary也可以直接获取
{
ErlNifBinary bin;//ErlNifBinary 有两个属性,data和size,分别储存数据和长度,注意断点看看
enif_inspect_binary(env, argv[0], &bin);
res = enif_make_list_cell(env, enif_make_binary(env, &bin), res);
}
4. atom类型
typedef struct
{
int len;//长度
char list[0];
}ERL_ATOM;
if (enif_is_atom(env, arg))//atom
{
ERL_ATOM* atom = NULL;
get_atom(env, arg, &atom);
res = enif_make_list_cell(env, mk_atom(env, atom->list), res);
}
因为长度不定,所以atom稍微复杂些,使用了一个结构体,动态储存atom
ERL_NIF_TERM mk_atom(ErlNifEnv* env, char* atom)
{
ERL_NIF_TERM ret;
if (!enif_make_existing_atom(env, atom, &ret, ERL_NIF_LATIN1))
{
return enif_make_atom(env, atom);
}
return ret;
}
/**
* 获取一个atom
* 成功返回1,失败返回0
*/
int get_atom(ErlNifEnv* env, ERL_NIF_TERM atom, ERL_ATOM** atomPoint){
int len = 0;
enif_get_atom_length(env, atom, &len, ERL_NIF_LATIN1);
if (len>0){
ERL_ATOM* atom1 = malloc(sizeof(ERL_ATOM)+sizeof(char)*len);
atom1->len = len;
if (!enif_get_atom(env, atom, atom1->list, len + 1, ERL_NIF_LATIN1)) {//因为char列表是以'\0'作为结束,所以要len+1
return 0;
}
*atomPoint = atom1;
return 1;
}
return 0;
}
5. list类型
if (enif_is_list(env, arg))//list
{
ERL_LIST* listPoint;
get_string(env, arg, &listPoint);
}
假设这个list就是一个单纯的string(如果是复杂list,还需要重新循环解析每个cell)
/*
* 获取一个string
* 成功返回1,失败返回0
**/
int get_string(ErlNifEnv* env, ERL_NIF_TERM args, ERL_LIST** listPoint){
if (enif_is_list(env, args)){
ERL_NIF_TERM listItem;//list cell的缓存
int cache = 0;//缓存当前list cell的asc编码
int lenList = 0;//列表长度
int index = 0;//char列表的赋值标记
enif_get_list_length(env, args, &lenList);
ERL_LIST* list = malloc(sizeof(ERL_LIST)+lenList*sizeof(char));
while (enif_get_list_cell(env, args, &listItem, &args)) {
enif_get_uint(env, listItem, &cache);
(list->list)[index] = (unsigned char *)cache;
index++;
}
list->len = lenList;
ERL_NIF_TERM res = enif_make_list(env, 0);
for (int i = lenList; i > 0; --i)
{
res = enif_make_list_cell(env, enif_make_int(env, (list->list)[i - 1]), res);
}
*listPoint = list;
return 1;
}
return 0;
}
///返回一个列表
static ERL_NIF_TERM mk_list(ErlNifEnv* env, int len, int array[]){
ERL_NIF_TERM res = enif_make_list(env, 0);
for (int i = 0; i < len; ++i)
{
res = enif_make_list_cell(env, enif_make_int(env, array[i]), res);
}
return res;
}
- 6.