如何使用Erlang端口将整数传递给C代码

时间:2014-07-22 13:40:49

标签: erlang

我已经提到Erlang Interoperability Tutorial User's Guide并实现了complex.c complex5.erl和port_driver.c

但是可以传递的数据大小限制为1 byte。 我浏览了文档并在complex5.erl

中传递了这个附加参数
init(SharedLib) ->
    register(code, self()),
    Port = open_port({spawn, SharedLib}, [{packet, 4}]),
    loop(Port).

更改:传递了元组 {packet, 4}

并在port_driver.c中进行了以下更改:

static void example_drv_output(ErlDrvData handle, char *buff, 
                   ErlDrvSizeT bufflen) {
    example_data* d = (example_data*)handle;
    char fn = buff[0],  res;
    char arg[100];
    getAddress(buff, arg);
    if (fn == 1) {
      res = foo(arg);
    } else if (fn == 2) {
      res = bar(arg);
    }
    driver_output(d->port, &res, 4);
}

更改: driver_output(d->port, &res, 4);

我将代码保留为编码并解码不变

encode({foo, X}) -> [1, X];
encode({bar, Y}) -> [2, Y].

decode([Int]) -> Int.

使用背景:

loop(Port) ->
    receive
    {call, Caller, Msg} ->
        Port ! {self(), {command, encode(Msg)}},
        receive
        {Port, {data, Data}} ->
            Caller ! {code, decode(Data)}
        end,
        loop(Port);
    stop ->
        Port ! {self(), close},
        receive
        {Port, closed} ->
            exit(normal)
        end;
    {'EXIT', Port, Reason} ->
        io:format("~p ~n", [Reason]),
        exit(port_terminated)
    end.

Foo功能:

int foo(int x) {
  return 500;
}

但我现在得到错误:

Error in process <0.47.0> with exit value: {function_clause,[{complex,decode,[[252,1,192,135]],[{file,"complex.erl"},{line,62}]},{complex,loop,1,[{file,"complex.erl"},{line,45}]}]}

我是否需要进行任何其他更改,否则,如何从C代码发送整数和接收整数?

编辑:我通过将解码功能修改为以下内容来消除错误:

decode(Int) -> 
    Bin=list_to_binary(Int),
    <<N:32 /integer>> = Bin, 
    N.

但是现在,当我打电话给foo时,N的值为 4093707712

2 个答案:

答案 0 :(得分:2)

对port_driver.c的以下修改解决了这个问题。

static void example_drv_output(ErlDrvData handle, char *buff, 
                       ErlDrvSizeT bufflen)
    {
        example_data* d = (example_data*)handle;
        char fn = buff[0], arg = buff[1];
        int* res =(int*)malloc(sizeof(int));
        if (fn == 1) {
          *res = htonl(foo(arg));
        } else if (fn == 2) {
          *res = htonl(bar(arg));
        }
        driver_output(d->port, (char*)res, 4);
    }

htonl()函数将无符号整数hostlong从主机字节顺序转换为网络字节顺序。

答案 1 :(得分:0)

解码函数在编写时,需要一个完整的元素列表:[Int],而消息是4个元素的列表:[252,1,192,135]

这不是那么糟糕,因为您似乎成功将消息{self(), {command, encode(Msg)}}发送到C端口,它已被理解,并且返回的值被解释为{Port, {data, Data}},其中Port具有正确的值

查看链接中的代码,当您获得4个整数的列表时,Data应该是一个整数。我想你在驱动程序中做出的修改以及选项{packet, 4}对此负责。