免責事項: 質問の作成者は、Erlang の平均的な知識と、C の基本的な (ただし増加中の) 知識を持っています。
この関数を使用して、プログラムがInteroperability Tutorial User Guideで提供されている Erlang ポートの例から取得しread()
たバイトを読み取ります(「Erlang Programming」本の第 12 章にも説明されています)。port.c
しかし、私が得た間違った値 (例えば、999 ではなく 231) は C 側から来ているため、この質問は Erlang にまったく関係がないと考える傾向があります。
問題は、このプロトコルが 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 ポート:
/* port.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;
しかし、うまくいきませんでした。
実際には、次の 2 つの問題があります。
- 255 より大きいパラメータでポートを呼び出すと (たとえば
foo(256)
、Erlang ポートから)、実行は read_cmd() 内の i = 0 の read() で終了します。 - 255 未満のパラメーターでポートを呼び出したが、関数の結果が 255 を超えた場合 (たとえば
int foo(int x) { return x+1000; }
、プログラムは終了しませんが、Erlang ポートに予期しない値が返されます。
問題は、プロトコルをより大きな数や浮動小数点数で動作させるにはどうすればよいかということです。