Erlang内建函数与C的数据转换

前言:本人不是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;
}
  1. 6.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值