4

C Structを初期化し、別のRubyオブジェクトのパラメーターとしてRubyクラスとしてラップする方法は?メモリを書き換えていますが、修正方法がわかりません。

Rubyコード、Personクラスのインスタンスを作成し、それらにAddress変数を追加します。これは別のクラスです。

require_relative 'my_extension'

class Address
  def inspect
    "Replaced #inspect: <Address: town:#{town}>"
  end
end

class Person
    def initialize
        puts "init"
    end

    def print()
        puts "Addr class #{@addr.inspect}"
    end
end

foo1=Person.new
foo1.add_address("London")
foo1.print
foo2=Person.new
foo2.add_address("Paris")
foo1.print
foo2.print
foo1.print

Rubyを拡張するCコード:

#include <stdio.h>
#include "ruby.h"

struct Address {
    char * town;
};

static VALUE get_addr(VALUE self) {
    return rb_iv_get(self,"@addr");
}

static VALUE wrap_address_get_town(VALUE self) {

    struct Address * address;
    Data_Get_Struct(self, struct Address, address);
    return rb_str_new2(address->town);
}


VALUE foo_class;
VALUE address_wrapper_class;


void free_m(){
    printf("free\n");//just for test
}

void add_address_t(VALUE self,VALUE new_town){
    printf("add_address\n");
    /*init new struct and add value to it*/
    struct Address addr;
    addr.town=StringValuePtr(new_town);

    /*wrap struct*/
    VALUE wrapped_address=Data_Wrap_Struct(address_wrapper_class, 0, free_m,&addr);

    /*set it as instance variable*/
    rb_iv_set(self,"@addr",wrapped_address);
}

static VALUE foo_class_alloc(VALUE self){
    return self;
}


void Init_my_extension(){
    foo_class = rb_define_class("Person", rb_cObject);

    address_wrapper_class = rb_define_class("Address", rb_cObject);

    rb_define_method(address_wrapper_class, "town", wrap_address_get_town, 0);

    rb_define_method(foo_class, "add_address", add_address_t, 1);

}

出力は予期しない結果を生成します:

init
Addr class Replaced #inspect: <Address: town:London>
init
Addr class Replaced #inspect: <Address: town:Paris> //London expected
Addr class Replaced #inspect: <Address: town:�)> //another problem
Addr class Replaced #inspect: <Address: town:�)>
run
run
free
free
4

2 に答える 2

1

FFI gemは、やりたいことを達成するためのより良い方法を提供する可能性があります。

require 'ffi'  
module AddressModule
   extend FFI::Library
   ffi_lib '<path to your c library>'

   class Address < FFI::Struct
      layout :address, :string,
   end
end

person = AddressModule::Address.new
person[:address] = "an address"

または何でも。https://github.com/ffi/ffi/wikiでFFIドキュメントを確認してください

于 2012-04-19T21:41:58.843 に答える
0

すべてのCルーチンは、値を返す静的として定義する必要があります。関連するものが何も返されない場合、これはQnilである必要があります。ルーチンには別の問題もありadd_address_tます-ローカルで定義された構造体をラップしています-それはで割り当てられる必要がありますALLOC(struct Address);

于 2012-04-19T21:20:24.043 に答える