免责声明:该问题的作者对 Erlang 有一般的了解,并且对 C 有基本的(但不断增加的)知识。
我正在使用该read()
函数来读取我的程序从互操作性教程用户指南port.c
中提供的 Erlang 端口示例中获取的字节(它也在“Erlang 编程”一书的第 12 章中进行了描述)。
但我倾向于认为这个问题根本与 Erlang 无关,因为我得到的错误值(例如 231 而不是 999)来自 C 端。
问题是该协议不适用于超过 255 的参数(否则效果很好)。我想它与byte
类型和read_exact()
实现有关,但我不知道如何修复它或使其可以在float
其中传递值。
为了理解这段代码,我已经阅读了一半的 K&R 书,但我仍然卡住了。
这是代码:
实际的 C 函数:
/* complex.c */
int foo(int x) {
return x+1;
}
int bar(int y) {
return y*2;
}
C 端口:
/* 端口.c */
typedef unsigned char byte;
int main() {
int fn, arg, res;
byte buf[100];
while (read_cmd(buf) > 0) {
fn = buf[0];
arg = buf[1];
if (fn == 1) {
res = foo(arg);
} else if (fn == 2) {
res = bar(arg);
}
buf[0] = res;
write_cmd(buf, 1);
}
}
缓冲区管理:
/* erl_comm.c */
typedef unsigned char byte;
read_cmd(byte *buf)
{
int len;
if (read_exact(buf, 2) != 2)
return(-1);
len = (buf[0] << 8) | buf[1];
return read_exact(buf, len);
}
write_cmd(byte *buf, int len)
{
byte li;
li = (len >> 8) & 0xff;
write_exact(&li, 1);
li = len & 0xff;
write_exact(&li, 1);
return write_exact(buf, len);
}
read_exact(byte *buf, int len)
{
int i, got=0;
do {
if ((i = read(0, buf+got, len-got)) <= 0)
return(i);
got += i;
} while (got<len);
return(len);
}
write_exact(byte *buf, int len)
{
int i, wrote = 0;
do {
if ((i = write(1, buf+wrote, len-wrote)) <= 0)
return (i);
wrote += i;
} while (wrote<len);
return (len);
}
二郎端口:
-module(complex1).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).
start(ExtPrg) ->
spawn(?MODULE, init, [ExtPrg]).
stop() ->
complex ! stop.
foo(X) ->
call_port({foo, X}).
bar(Y) ->
call_port({bar, Y}).
call_port(Msg) ->
complex ! {call, self(), Msg},
receive
{complex, Result} ->
Result
end.
init(ExtPrg) ->
register(complex, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
loop(Port).
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}},
receive
{Port, {data, Data}} ->
Caller ! {complex, decode(Data)}
end,
loop(Port);
stop ->
Port ! {self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
exit(port_terminated)
end.
encode({foo, X}) -> [1, X];
encode({bar, Y}) -> [2, Y].
decode([Int]) -> Int.
我做了一个愚蠢的改变尝试
typedef unsigned char byte;
至
typedef int byte;
但它没有用。
其实有两个问题:
- 如果我们使用大于 255 的参数调用端口(例如
foo(256)
来自 Erlang 端口),则执行将在 read_cmd() 中的 read() 处终止,其中 i = 0; - 如果我们使用小于 255 的参数调用端口,但函数的结果大于 255(例如
int foo(int x) { return x+1000; }
,程序不会终止,但我们的 Erlang 端口会得到一些意外的值;
所以,问题是:我应该怎么做才能使协议使用更大的数字甚至浮点数?