123456789_123456789_123456789_123456789_123456789_

An example

This FFI::Struct (meant to mirror a C struct), has a single value, named “value”, of type “double”

class SimpleStruct < FFI::Struct
  layout :value, :double
end

a = SimpleStruct.new # does a malloc on one of those structs

a[:value] = 32 # sets its internal value to 32

Passing structs as value or pointer parameters to functions

Assuming you have a C library that looks like this, where the function takes a struct as an argument by value:

typedef struct _WHAT {
  int d;
} WHAT;

int doit_by_value(WHAT w) {
  printf("%d\n", w.d);
  return w.d;
}

int doit_by_ptr(WHAT *w) {
  printf("%d\n", w->d);
  return w->d;
}

The resulting FFI wrapper code for the function should look like this:

class WHAT < FFI::Struct
  layout :d, :int
end
attach_function 'doit_by_value', [ WHAT.by_value ], :int
attach_function 'doit_by_ptr', [ WHAT.by_ref ], :int

w = WHAT.new
w[:d] = 123
Foo.doit_by_value(w)
Foo.doit_by_ptr(w)

StackOverflow Question Relating to this

When allocated

When you call FFI::Struct.new, it allocates an “internal bytes” worth of memory right then. When you then do a set, like struct[:member] = 3, the bits within that struct are set right then. The inverse is also true; x = struct[:member] does a read from the raw memory (and translation into a ruby object), each time you access it. Memory is “zeroed out” when it is first allocated, unless you pass in your own Pointer or specify it to not clear memory (additional notes). If you pass it a Pointer it basically uses that as its base instead of allocating anything.

# Pass false as a 3rd argument to skip memory initialization
pointer = FFI::MemoryPointer.new :char, SimpleStruct.size, false
a = SimpleStruct.new pointer

Note that you can get the actual address of the struct by using the #pointer method.

Casting

The same technique can be used to cast a “formless” blob of memory to a struct.

class ComplexStruct < FFI::Struct
  layout :context, :pointer,
    :value1, :int32,
    :value2, :uint64,
    :value3, :char,
    :next, :pointer
end

def cast_to_complex_struct pointer
  ComplexStruct.new pointer
end

Calling cast_to_complex_struct and passing it a blob of memory will return a struct object mapped to that memory location. Code can then directly access the struct fields and operate on them.

my_struct = cast_to_complex_struct(FFI::MemoryPointer.new :char, ComplexStruct.size)
my_struct[:value1] = rand(1000)
my_struct[:value2] = my_struct[:value1] * my_struct[:value3]

Nested Structs

It’s possible to nest structs within one another by direct reference. Simply use the name of the struct type you wish to nest within another. If instead you need a pointer to a struct of that type, use the next section, “Nested pointers” for more information.

class InnerStruct < FFI::Struct
  layout :messageLength,  :uint32,
         :pMessage,       :string
end

class OuterStruct < FFI::Struct
  layout :value,  :uint32,
         :inner,  InnerStruct  # this sets up our inner struct!
end

Nested pointers

You can define nested pointers to structs within structs using FFI::Struct.ptr method. It’s important to keep in mind, that each object stored in a pointer reference needs to stored in a ruby variable, so that it isn’t garbage collected until the struct is no longer accessed. See Core Concepts for more description about memory management.

class Struct2 < FFI::Struct
  layout :age, :int
end

class Struct1 < FFI::Struct
  layout :id, :int,
    :data, Struct2.ptr
end

struct = Struct1.new
struct2 = Struct2.new
struct[:data] = struct2
struct[:data][:age] = 27

Don’t reference the inner Struct2 object by a pointer only! The ruby garbage collector doesn’t know about it and could free the memory behind Struct2 before the data has been processed. So this is dangerous: ```ruby struct = Struct1.new struct[:data] = Struct2.new # Struct2.new object could be GC’ed immediately! struct[:data][:age] = 27

Pointers to Functions

Some libraries have factory functions that return structures containing pointers to other functions in the library. Instead of modeling these pointers using the normal :pointer type, you can simply create an anonymous or named callback type using the callback method.

class FunctionTable < FFI::Struct
  layout :function1, callback([:pointer, :int], :void)  # A pointer to an anonymous function that takes a pointer and an integer

  # or more verbose with a named callback:
  layout :function1, :completion_function  # A pointer to the named callback function
end

callback :completion_function, [:pointer, :long, :uint8], :void  # define a named callback
attach_function :factory, [], :FunctionTable.by_ref

Then, once the factory function has filled in the pointers, you can call them using the regular call() method.

vtable = factory()        # Creates and returns a new structure

# Call the function that the library provided
vtable[:function1].call(my_pointer, my_integer)

Char arrays

from C

struct { 
  uint8 Value; 
  uint8 String[SIZE_OF_ARRAY]; 
} MyArray_t; 

to Ruby

class MyArray_t < FFI::Struct 
  layout  :Value,  :uint8, 
         :String, [:uint8, SIZE_OF_ARRAY] 
end 

# use via:
my_array_struct[:String].to_ptr.read_string

Set them like

a = MyArray_t.new
a[:String][0] = 33 # set a single byte within the struct

or

a[:String].to_ptr.put_string(0, "foo")

custom packed structs

By default, ffi will assume the structs you mentioned are to be packed “like normal for your system” — if this is not the case, as in if you use #pragma pack in msvc, or __attribute__((__packed__)) on gcc, then you’ll need to specify the struct packing boundary.

class CustomPacked < FFI::Struct
  pack 1  # pack all members on a 1 byte boundary
  layout :a, :char,
         :b, :int, # starts at offset=1, not offset=4
end

Array of Structs

You can access an array of structs by stepping through the array in increments of the struct size, and casting each blob of memory using FFI::Pointer#.

Here is an example of a parent struct that contains an array of structs, and each member of the array also contains a union.

From c:

 // parent struct contains an array of child structs in *val
 typedef struct {
    uint len;
    F_TextItemT *val;
 } F_TextItemsT;

 typedef struct {
    int offset;
    int dataType; // indicates what part of the union is valid
    union {
	 char *sdata;  // string data
	 int idata;  // int data
	 } u;
    } F_TextItemT;

In Ruby the structs and union look like this:

class FTextItemU < FFI::Union
  layout :sdata, :string,
  :idata, :int
end

class FTextItemT < FFI::Struct
  layout  :offset, :int,
    :dataType, :int,
    :u, FTextItemU
end 

class FTextItemsT < FFI::Struct
  layout :len, :uint,
    :val, :pointer
end

This code accesses members of the array using FFI::Pointer# by stepping through the array at increments of the struct size:

tis = FM.FApiGetText(docid, flowid, (FM.FTIString | FM.FTILineEnd));
# Traverse text items and print strings and line ends.
 0.upto(tis[:len]-1)  do |i|
   s = FM::FTextItemT.new(tis[:val] + (i * FM::FTextItemT.size))
   if s[:dataType] == FM.FTIString
     puts s[:u][:sdata]
   end
 end

Alternatively, you can use Pointer.new() to create a new pointer with a different type_size (the size used to step along it using the [] method).

e.g.

val_array = FFI::Pointer.new(FM::FTextItemT, tis[:val])
0.upto(tis[:len]) do |i|
   s = FM::FTextItemT.new(val_array[i])
   # do stuff with s struct here
end

If you need to pass an array of structs to a function, you can use the same approach: first pre-allocate some memory for the array, and then step through it. If you wish, you can create an array of Ruby objects, each of which points to the correct place in the underlying storage. The following example uses struct iovec as used by sendmsg(2) and recvmsg(2)

class IOVec < FFI::Struct
  layout :base, :pointer,
         :len, :size_t
end

iovlen = 3
iov = FFI::MemoryPointer.new(IOVec, iovlen)
iovs = iovlen.times.collect do |i|
  IOVec.new(iov + i * IOVec.size)
end

iovs[0][:base] = #...
iovs[0][:len]  = #...
iovs[1][:base] = #...
iovs[1][:len]  = #...
iovs[2][:base] = #...
iovs[2][:len]  = #...

msghdr.msg_iov = iov
msghdr.msg_iovlen = iovlen

Simpler struct arrays

An easier way to handle arrays of structs is to use a single memory pointer.

class SomeStruct < FFI::Struct
  # . . .
end

# where length is the size of the array
ary = FFI::MemoryPointer.new( :uchar, SomeStruct.size() * length )

This can be passed directly into a C-function and will have the requisite memory allocated to it to contain all instances of the struct you’re using.

To read out of it again, simply do the following:

# determine the length of the data
bytes = SomeStruct.size()

# read a struct from a single index; this requires two steps:
# 1. first we declare the container pointer.
# 2. then we cast it.
data = ary.slice( bytes * index, bytes )
instance_of_somestruct = SomeStruct.new( data )

If you would rather read the entirety of the pointer as a ruby Array, you can instead do this:

# determine the length of the data
bytes = SomeStruct.size()

# create an array
instances_of_somestruct = Array.new( ary.size / bytes ){|index|
  # set this index to the new SomeStruct instance
  SomeStruct.new( ary.slice( index * bytes, bytes ) )
}

Getting Pointers to Struct Fields

Some functions need the address of a field to be passed as an argument. There is no built-in method for returning a field’s address. Luckily we can mimic this behavior by using a {FFI::Pointer} and a field offset.

 struct in_addr {
    uint32_t s_addr; // that's a 32-bit int (4 bytes)
 };

 struct sockaddr_in {
    short int          sin_family;  // Address family, AF_INET
    unsigned short int sin_port;    // Port number
    struct in_addr     sin_addr;    // Internet address
    unsigned char      sin_zero[8]; // Same size as struct sockaddr
 };

 char* result;
 char ip_string[INET_ADDRSTRLEN];
 struct sockaddr_in sa;      // pretend this is loaded with something

 result = inet_ntop(AF_INET, &(sa.sin_addr), ip_string, INET_ADDRSTRLEN);

<pre class="code"><code class="">
Translating this to Ruby is fairly straightforward.

<pre class="code ruby"><code class="ruby"> class SockAddrInStruct < FFI::Struct
   layout :sin_len, :uint8,
     :sin_family, :sa_family_t,
     :sin_port, :ushort,
     :sin_addr, :uint32,
     :sin_zero, [:uint8, 8]
 end

 attach_function :inet_ntop, [:int, :pointer, :pointer, :int], :string, :blocking => true

 ip_string = FFI::MemoryPointer.new(:uint8, INET_ADDRSTRLEN)

 sa = SockAddrInStruct.new # pretend this is loaded with something
 field_ptr = FFI::Pointer.new(:uint8, sa.pointer.address + sa.offset_of(:sin_addr))

 result = inet_ntop(AF_INET, field_ptr, ip_string, INET_ADDRSTRLEN);

Gotchas

multidimentional arrays aren’t yet fully supported

any type of class descendancy/hierarchy is not supported, at least it appears to not be.

Helpers

Currently structs only allow access “like a Hash” via instance[:member]. If you desire methods for access, you can use ffi swig, or nice-ffi or roll your own

Helper example via “method_missing” builtin

You can make a simple helper method to access struct members as if they were created with `attr_accessor` with the following code, which exploits the `method_missing()` builtin method for most Ruby objects:

class FFI::Struct

  # Use the symbol passed from the method for accessing the analogous field.
  # This method can also take a &block, but we would not use it.
  def method_missing( sym, *args )
    # convert symbol to a string to allow regex checks
    str = sym.to_s
    
    # derive the member's symbolic name
    member = str.match( /^([a-z0-9_]+)/i )[1].to_sym

    # raise an exception via the default behavior if that symbol isn't a member!
    super unless members.include? member

    # this ternary checks for the presence of an equals sign (=) to indicate an
    # assignment operation and changes which method we invoke and whether or not
    # to send the splatted arguments as well.
    (str =~ /=$/) ? send( :[]=, member, *args ) : send( :[], member )
  end
end

Platform dependent offsets of struct members

Offsets of struct members are calculated based on the value types. There is a deprecated way to define offsets explicit by using [[Automatic Struct Layout]].