2

以下は、C コードを呼び出して操作する必要がある R で 3 つの行列を作成する最小限の例です

要するに、行列 A を R から C に渡し、いくつかの値を W 行列と H 行列にコピーしたいと考えています。後者の2つは、変更された値でRに戻したいです。

ただし、これはうまくいきません ( segfault、または空の行列が返されます)。R はオブジェクトを参照渡しするのではなく、C で使用するためにコピーしていると思われます。

C ソース (test.c):

void test(double *A, double *W, double *H, int m, int n, int k) {
    // A is input with dimensions (m,n)
    // W has dimensions (m,k)
    // H has dimensions (k,n)

    int i;

    for(i=0; i<m*k; i++)
        W[i] = A[i];

    for(i=0; i<k*n; i++)
        H[i] = A[i];
}

いくつかのビルド手順 (Makefile):

CCFLAGS = -fPIC

all: shared

shared: test.o
    $(CC) -shared -Wl,-soname,test.so -o test.so test.o

test.o: test.c
    $(CC) $(CCFLAGS) -c $<

それを呼び出す R コードは次のとおりです。

dyn.load("test.so")

m = 3
n = 3
k = 2

A = matrix(c(1:(m*n)), nrow=m, ncol=n)

W = matrix(0, nrow=m, ncol=k)
H = matrix(0, nrow=k, ncol=n)

.C("test", as.double(A), as.double(W), as.double(H), 
   as.integer(m), as.integer(n), as.integer(k))

今私の質問:

  • ほとんどの場合、このセグメンテーション違反が発生するのはなぜですか?
  • 初期化されていない R 行列で C 関数を呼び出す方法はありますか?
  • 「void」関数が何かを返すのはなぜですか?

最も重要な、

  • これを機能させる方法は?
4

1 に答える 1

1
  • ほとんどの場合、このセグメンテーション違反が発生するのはなぜですか?

これは(おそらく)関数が整数を受け取るのに対し、.Cインターフェイスはポインターを渡すためです。あなたの署名は

void test(double *A, double *W, double *H, int *m, int *n, int *k)
  • 初期化されていない R 行列で C 関数を呼び出す方法はありますか?

DUP=FALSEへの呼び出しを設定する.C.C、渡した配列がコピーされなくなります。詳細?.Cについては、を参照してください。

  • 「void」関数が何かを返すのはなぜですか?

C 関数は何も返しませんが、R 関数.Cは C 関数に渡された引数に対応するリストを返します。もう一度、 を参照してください?.C

  • これを機能させる方法は?

選択肢は 2 つあります。DUP=FALSE1 つ目は、既存の R オブジェクトを設定し、C 関数で変更できるようにすることです。as.doubleただし、これを行う場合は、それらを外部呼び出しに渡す前に呼び出すことを確認する必要があります。そうしないと、現在定義されているように整数型になるためas.double、新しいオブジェクトの作成が強制されます。WH

2 番目の選択肢は、次のように を離れて、呼び出しDUP=TRUEからの戻り値を使用することです。.C

result<-.C("test", as.double(A), W=as.double(W), H=as.double(H), 
  as.integer(m), as.integer(n), as.integer(k))
W<-result$W
H<-result$H
于 2013-10-25T23:03:49.047 に答える