LoginSignup
3
1

More than 5 years have passed since last update.

Rubyからc言語の関数に構造体を渡す

Posted at

最近Rubyからdllとかsoとか、割と簡単(?)に呼び出せることを知りました。
自分のやったことを整理しています。

C側(呼び出す対象->よくわかっていない)

sample.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//社員の給与
typedef struct salary {
    long amount;
    long family;
    long bonus;
} SAL;

// 社員構造体
typedef struct employee {
    long no;
    char name[20];
    int service;
    SAL salary;
} EMP;

int main(void)
{
    struct employee e[20]= {
        { 1, "将来 有望",5, 201234, 10000, 350123 },
        { 0, "", 0, 0, 0,0 },
    };
    struct employee *emp;
    int i;

    emp = e;

    for(i = 0; emp->no != 0; i++) {
        printf("%s total = %ld\n", 
            emp->name,
            emp->salary.amount + emp->salary.family);
        emp++;
    }

    return 0;
}

extern "C" int call(EMP *a,EMP *b){

    printf("a-size : %lu\n",sizeof(*a));
    printf("b-size : %lu\n",sizeof(*b));

    //渡された名前をかくにん
    printf("%s\n",a->name);

    EMP *c;
    //構造体配列
    c = (EMP *)malloc(sizeof(EMP) * 5);
    c = b;
    //rubyから渡した値をコピー
    c[0].no = a->no;
    strcpy(c[0].name,a->name);
    c[0].salary.amount = a->salary.amount;
    c[1].no = 77777;
    strcpy(c[1].name,"薄給 涙");
    c[1].salary.amount = 170077;

    //値の変更
    strcpy(a->name,"test_name_moded");


    return 1;
}

ビルド(MACで実行した)
gcc -shared sample.cpp -o lib_sample.so

call_.rb
require "fiddle/import"

module M
  extend Fiddle::Importer
  dlload "./lib_sample.so"
  extern "int main()"
  extern "int call(void *,void *)"
  #構造体の入れ子はバラすのがポイント(と聞いた)
  EMP = struct(["long a","char b[20]","int c","long x","long y","long z",])  
end
x = M::EMP.malloc
y = Fiddle::Pointer.malloc(M::EMP.size * 5)

x.a = 1
x.b = "test name".unpack("c*") + [0] * (20 - 4)
x.c = 1
x.x = 100000
M.call(x,y)
p "x:"
p x.b.pack("c*").force_encoding("utf-8")
p "x[0] = a:#{x.a},b:#{x.b.pack("c*")},x:#{x.x}"
y_ret = M::EMP.new(y)
p "y[0] = a:#{y_ret.a},b:#{y_ret.b.pack("c*")},x:#{y_ret.x}"
#ポインタずらし
yp = y + M::EMP.size
y_ret2 = M::EMP.new(yp)
p "y[1] = a:#{y_ret2.a},b:#{y_ret2.b.pack("c*").force_encoding("utf-8")},x:#{y_ret2.x}"
実行結果.
"x[0] = a:1,b:test_name_moded\u0000\u0000\u0000\u0000\u0000,x:100000"
"y[0] = a:1,b:test name\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000,x:100000"
"y[1] = a:77777,b:薄給 涙\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000,x:170077"

あまりわかってない感が満載でした。以上。

3
1
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
3
1