From: Hirotsugu Asari Date: 2009-05-10T08:56:01+09:00 Subject: [ruby-core:23414] Re: ruby-ffi problem --Apple-Mail-1--534331811 Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit If you want to change the string value of a field in a struct through FFI, I suggest using the ":pointer" rather than ":string". =cut require 'rubygems' require 'ffi' module LibTest class Info < FFI::Struct layout :name, :pointer, :val, :double end extend FFI::Library ffi_lib './libtest.dylib' attach_function :create, [:string, :double], :pointer attach_function :show, [:pointer], :int end include FFI ptr = LibTest.create( "test string", 11.27) obj = LibTest::Info.new(ptr) LibTest.show(ptr) obj[:val] = 27.11 obj[:name].put_bytes(0,'new string') LibTest.show(ptr) =end In the long run, as Charlie suggested, your question will be better answered by ruby-ffi project. -- Hirotsugu Asari On May 9, 2009, at 4:48 AM, Aston wrote: > Hello, > > I am trying to learn ruby-ffi now (after sadly leaving dl library), > I have some trouble here too > > I will present a simple example where I want to pass a struct > between ruby and C > I am facing problems while setting fields of struct if that field is > of type string(char*, not char[]) > I understand we have to allocate the char* field of struct first > than assign some literal srting > > consider the C file > > ********************** C FILE********************** > #include > #include > #include > > typedef struct > { > char *name; > double val; > } INFO, *INFO_PTR; > > INFO_PTR create( char* name, double val) > { > INFO_PTR p = (INFO_PTR)malloc( sizeof(INFO)); > p->val = val; > p->name = (char*)malloc( strlen(name) + 1); > strcpy( p->name, name); > return p; > } > > int show( INFO_PTR pInfo) > { > return printf( "%s - %f\n", pInfo->name, pInfo->val); > } > > ********************** END C FILE********************** > > ********************** RUBY FILE********************** > require 'ffi' > > module LibTest > class Info < FFI::Struct > layout :name, :string, > :val, :double > end > > extend FFI::Library > ffi_lib "./libtest.so" > attach_function :create, [:string, :double], :pointer > attach_function :show, [:pointer], :int > end > > include FFI > > ptr = LibTest.create( "test string", 11.27) > obj = LibTest::Info.new(ptr) > LibTest.show(ptr) > obj[:val] = 27.11 # this works > # obj[:name] = "new string" # this gives error, `[]=': Cannot > set :string fields (ArgumentError) > LibTest.show(ptr) > ********************** END RUBY FILE********************** > > how can I set string values from ruby ? > If I refuse to declare name field as type char[] from char* then I > have to allocate before I can assign > then my approach below core dumps :( > > 1 str = "test string" > 2 p = MemoryPointer.new( str.size) > 3 p.write_string(str) > 4 puts p.read_string # "test string" > 5 obj[:name].write_pointer(p) # core dumps here! > > line # 5 core dumps everytime one tries to write anything there, > since pointer is invalid I guess > how do I allocate memory there ? once allocated can i treat that > allocated memory as ruby string ? > > Goal I want to achieve is I shall allocate in ruby, assign in ruby > and pass in to C code only for modification or read only purpose > how do I go from here ? can you comment on this ? > > Aston > > > Now surf faster and smarter ! Check out the new Firefox 3 - Yahoo! > Edition * Click here! --Apple-Mail-1--534331811 Content-Type: text/html; charset=US-ASCII Content-Transfer-Encoding: quoted-printable If you want to change the = string value of a field in a struct through FFI, I suggest using the = ":pointer" rather than = ":string".

=3Dcut

require= 'rubygems'
require 'ffi'

module = LibTest
  class Info < = FFI::Struct
    layout :name, = :pointer,
           :val, = :double
  end

  ext= end FFI::Library
  ffi_lib = './libtest.dylib'
  attach_function :create, = [:string, :double], :pointer
  attach_function = :show, [:pointer], :int
end

include = FFI

ptr =3D LibTest.create( "test string", = 11.27)
obj =3D = LibTest::Info.new(ptr)
LibTest.show(ptr)
obj[:val] =3D= 27.11
obj[:name].put_bytes(0,'new = string')
LibTest.show(ptr)

=3Dend
=


In the long run, as Charlie = suggested, your question will be better answered by ruby-ffi = project.


On May 9, 2009, = at 4:48 AM, Aston wrote:

}

********************** END C = FILE**********************

********************** RUBY = FILE**********************
require 'ffi'

module = LibTest
  class Info < FFI::Struct
    = layout :name, = :string,
           = :val, :double
  end

  extend FFI::Library
  = ffi_lib "./libtest.so"
  attach_function :create, [:string, = :double], :pointer
  attach_function :show, [:pointer], = :int
end

include FFI

ptr =3D LibTest.create( "test = string", 11.27)
obj =3D = LibTest::Info.new(ptr)
LibTest.show(ptr)
obj[:val] =3D 27.11 # = this works
# obj[:name] =3D "new string" # this gives error, `[]=3D': = Cannot set :string fields = (ArgumentError)
LibTest.show(ptr)
********************** END RUBY = FILE**********************

how can I set string values from ruby = ?
If I refuse to declare name field as type char[] from char* then I = have to allocate before I can assign
then my approach below core = dumps :(

1 str =3D "test string"
2 p =3D MemoryPointer.new( = str.size)
3 p.write_string(str)
4 puts p.read_string # "test = string"
5 obj[:name].write_pointer(p) # core dumps here!

line = # 5 core dumps everytime one tries to write anything there, since = pointer is invalid I guess
how do I allocate memory there ? once = allocated can i treat that allocated memory as ruby string ?

Goal = I want to achieve is I shall allocate in ruby, assign in ruby and pass = in to C code only for modification or read only purpose
how do I go = from here ? can you comment on this = ?

Aston



Now surf = faster and smarter ! Check out the new Firefox 3 - Yahoo! Edition * Click = here!

= --Apple-Mail-1--534331811--