使用ruby FFI在ruby中创建静态数组类

Dav*_*mar 2 c ruby memory arrays ffi

我想在ruby中实现我自己的静态数组类。这将是一个具有固定容量的数组,并且该数组中的所有元素都是单一类型。为了直接访问内存,我正在使用FFI gem https://github.com/ffi/ffi,它可以创建您自己的C函数并将其用于ruby程序。我创建了一个非常简单的C函数,该函数为整数数组分配内存,并返回指向内存空间的指针:

int * create_static_array(int size) {
  int *arr = malloc(size * sizeof(int));
  return arr;
}
Run Code Online (Sandbox Code Playgroud)

这是我的ruby static_array类,它使用create_static_array:

require 'ffi'
class StaticArray
  attr_accessor :pointer, :capacity, :next_index
  extend FFI::Library

  ffi_lib './create_array/create_array.so'
  attach_function :create_static_array, [:int], :pointer

  def initialize(capacity)
    @capacity = capacity
    @pointer = create_static_array(capacity)
    @next_index = 0
  end
 # adds value to the next_index in array
  def push(val)
    @pointer[@next_index].write(:int, val)
    @next_index += 1
  end
 # reads value at index
  def [](index)
    raise IndexOutOfBoundException if index >= @capacity
    self.pointer[index].read(:int)
  end
 # print every value in index
  def print
    i = 0
    while (i <   @capacity)
      puts @pointer[i].read(:int)
      i += 1
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我添加了一些方法来与我的数组,推元素,读取索引处的元素进行交互...但是我的static_array实例不能完全按预期工作...

假设我写:

// creates a static array in memory which can store 4 ints
arr = StaticArray.new(4)
Run Code Online (Sandbox Code Playgroud)

现在让我们在arr中推一个int:

arr.push(20)
Run Code Online (Sandbox Code Playgroud)

arr.print 将输出

20
0
0
0
Run Code Online (Sandbox Code Playgroud)

这是有道理的。现在让我们将另一个int推入arr:

arr.push(16)
Run Code Online (Sandbox Code Playgroud)

arr.print再次:

4116
16
0
0
Run Code Online (Sandbox Code Playgroud)

20已经被4116取代了。。。我真的不能理解这里发生的事情吗?

如果对https://www.rubydoc.info/github/ffi/ffi/FFI/Pointer有帮助,这是指向FFIPointer类文档的链接

Fir*_*cer 5

FFI接口不知道指针的类型,因此它只是将其视为字节数组(请参见有关指针类型的初始化)。请注意,当您通过时:int,这是针对特定的write和的read,而不是您在进行索引的位置。因此,您正在以字节偏移量0、1、2、3而不是整数元素0、4、8、12进行写入和打印。

在具有32位,4字节int的little endian系统上,二进制值20是14 00 00 00和16是10 00 00 00

因此,您分配4 * 4字节,即32个字节,前8个为。

00 00 00 00 00 00 00 00
Run Code Online (Sandbox Code Playgroud)

并在偏移量0处写入20

14 00 00 00 00 00 00 00
Run Code Online (Sandbox Code Playgroud)

然后在偏移量1处写入16

14 10 00 00 00 00 00 00
Run Code Online (Sandbox Code Playgroud)

14 10 00 000x00001014或4116,然后在下一个偏移量处打印它10 00 00 00是16。