LoginSignup
2
2

More than 5 years have passed since last update.

CからNimの配列を得たい

Posted at

本日は

 ここで

でCからNimの配列を得ようとしましたが期待しない値を得てしまう現象が起きたので再トライします。

どうやら配列のメモリを確保した際に要素にアクセス仕方に工夫がいるようです。

Nimのフォーラム で議論されていることを参考にしました。

 実装

Nim側

test.nim

proc test_arr(): pointer {.exportc.} =
  var p = cast[ptr cfloat](alloc0 sizeof(array[3, cfloat]))

  cast[ptr cfloat](cast[ByteAddress](p) +% 0 * sizeof(p[]))[] = -1'f32
  cast[ptr cfloat](cast[ByteAddress](p) +% 1 * sizeof(p[]))[] = -2'f32
  cast[ptr cfloat](cast[ByteAddress](p) +% 2 * sizeof(p[]))[] = -3'f32
  return p

cast[ptr cfloat](cast[ByteAddress](p) +% index * sizeof(p[]))[] という書き方をするといいみたいです。

C側

main.c

#include<stdio.h>

extern void* test_arr();

int main(int argc, char const *argv[])
{
    float* a = (float*)test_arr();
    printf("%f\n", a[-1]); //dangerous
    printf("%f\n", a[0]);
    printf("%f\n", a[1]);
    printf("%f\n", a[2]);
    printf("%f\n", a[3]); //dangerous
    return 0;
}

コンパイル

次のような Makefile を作成し

main: libtest.a
    gcc -o main main.c libtest.a 

libtest.a:test.nim
    nim c --app:staticlib --noMain test.nim 

clean:
    rm -rf nimcache
    rm -f main
    rm *.a

さらにターミナルを起動して次を実行します。

$ ls
Makefile    main.c      test.nim
$ make
$ ./main
./main 
0.000000
-1.000000
-2.000000
-3.000000
0.000000

一応呼び出しは成功しているみたいです。

 テンプレートを使う

Nimのコードの方は p[index]=valueという直感的な記法でポインタの操作をできるようテンプレートを使うことも出来ます。

test.nim

#[
Reference:
https://forum.nim-lang.org/t/1188
]#

template ptrMath(body: untyped) =
  template `+`[T](p: ptr T, off: int): ptr T =
    cast[ptr type(p[])](cast[ByteAddress](p) +% off * sizeof(p[]))

  template `+=`[T](p: ptr T, off: int) =
    p = p + off

  template `-`[T](p: ptr T, off: int): ptr T =
    cast[ptr type(p[])](cast[ByteAddress](p) -% off * sizeof(p[]))

  template `-=`[T](p: ptr T, off: int) =
    p = p - off

  template `[]`[T](p: ptr T, off: int): T =
    (p + off)[]

  template `[]=`[T](p: ptr T, off: int, val: T) =
    (p + off)[] = val
  body


proc test_arr(): pointer {.exportc.} =
  ptrMath:
    var p = cast[ptr cfloat](alloc0 sizeof(array[3, cfloat]))
    var a: array[3, cfloat]
    for i in a.low..a.high:
      a[i] += 1'f32

    p[0] = a[0]-4'f32
    p[1] = a[1]-2'f32
    p[2] = a[2]-3'f32
  return p
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2