类 Fiddle::Pointer

Fiddle::Pointer 是一个用于处理 C 指针的类

属性

ffi_ptr[R]

公共类方法

[](value)

获取 ruby 对象 val 的底层指针,并将其作为 Fiddle::Pointer 对象返回。

别名为: to_ptr
from_native(value, ctx) 点击切换源代码
# File fiddle/lib/fiddle/ffi_backend.rb, line 236
def self.from_native(value, ctx)
  self.new(value)
end
malloc(size, free = nil) { |pointer| ... } 点击切换源代码

示例

# Automatically freeing the pointer when the block is exited - recommended
Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer|
  ...
end

# Manually freeing but relying on the garbage collector otherwise
pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
...
pointer.call_free

# Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe
pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
...

# Only manually freeing
pointer = Fiddle::Pointer.malloc(size)
begin
  ...
ensure
  Fiddle.free pointer
end

# No free function and no call to free - the native memory will leak if the pointer is garbage collected
pointer = Fiddle::Pointer.malloc(size)
...

分配 size 字节的内存,并将其与可选的 freefunc 相关联。

如果提供了代码块,则指针将传递给该代码块而不是被返回,并且将返回该代码块的返回值。如果存在代码块,则必须提供 freefunc

如果提供了 freefunc,它将在指针被垃圾回收时,或者当代码块被离开时(如果提供了代码块)或当用户调用 call_free 时,第一次发生时被调用。freefunc 必须是一个指向函数的地址,或者是 Fiddle::Function 的一个实例。

# File fiddle/lib/fiddle/ffi_backend.rb, line 338
def self.malloc(size, free = nil)
  if block_given? and free.nil?
    message = "a free function must be supplied to #{self}.malloc " +
              "when it is called with a block"
    raise ArgumentError, message
  end

  pointer = new(LibC.malloc(size), size, free)
  if block_given?
    begin
      yield(pointer)
    ensure
      pointer.call_free
    end
  else
    pointer
  end
end
new(addr, size = nil, free = nil) 点击切换源代码
# File fiddle/lib/fiddle/ffi_backend.rb, line 300
def initialize(addr, size = nil, free = nil)
  ptr = if addr.is_a?(FFI::Pointer)
          addr

        elsif addr.is_a?(Integer)
          FFI::Pointer.new(addr)

        elsif addr.respond_to?(:to_ptr)
          fiddle_ptr = addr.to_ptr
          if fiddle_ptr.is_a?(Pointer)
            fiddle_ptr.ffi_ptr
          elsif fiddle_ptr.is_a?(FFI::AutoPointer)
            addr.ffi_ptr
          elsif fiddle_ptr.is_a?(FFI::Pointer)
            fiddle_ptr
          else
            raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{fiddle_ptr.class}")
          end
        elsif addr.is_a?(IO)
          raise NotImplementedError, "IO ptr isn't supported"
        else
          FFI::Pointer.new(Integer(addr))
        end

  @size = size ? size : ptr.size
  @free = free
  @ffi_ptr = ptr
  @freed = false
end
Fiddle::Pointer.new(address) → fiddle_cptr 点击切换源代码
new(address, size) → fiddle_cptr
new(address, size, freefunc) → fiddle_cptr

创建一个指向 address 的新指针,带有可选的 sizefreefunc

当实例被垃圾回收时,将调用 freefunc

static VALUE
rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
{
    VALUE ptr, sym, size, wrap = 0, funcwrap = 0;
    struct ptr_data *data;
    void *p = NULL;
    freefunc_t f = NULL;
    long s = 0;

    if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) {
        VALUE addrnum = rb_Integer(ptr);
        if (addrnum != ptr) wrap = ptr;
        p = NUM2PTR(addrnum);
    }
    if (argc >= 2) {
        s = NUM2LONG(size);
    }
    if (argc >= 3) {
        f = get_freefunc(sym, &funcwrap);
    }

    if (p) {
        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        if (data->ptr && data->free) {
            /* Free previous memory. Use of inappropriate initialize may cause SEGV. */
            (*(data->free))(data->ptr);
        }
        RB_OBJ_WRITE(self, &data->wrap[0], wrap);
        RB_OBJ_WRITE(self, &data->wrap[1], funcwrap);
        data->ptr  = p;
        data->size = s;
        data->free = f;
    }

    return Qnil;
}
read(addr, len) 点击切换源代码

或者读取地址 address 处长度为 len 的内存,并返回包含该内存的字符串

# File fiddle/lib/fiddle/ffi_backend.rb, line 269
def self.read(addr, len)
  FFI::Pointer.new(addr).read_bytes(len)
end
to_native(value, ctx) 点击切换源代码
# File fiddle/lib/fiddle/ffi_backend.rb, line 224
def self.to_native(value, ctx)
  if value.is_a?(Pointer)
    value.ffi_ptr

  elsif value.is_a?(Integer)
    FFI::Pointer.new(value)

  elsif value.is_a?(String)
    value
  end
end
to_ptr(value) 点击切换源代码

获取 ruby 对象 val 的底层指针,并将其作为 Fiddle::Pointer 对象返回。

# File fiddle/lib/fiddle/ffi_backend.rb, line 240
def self.to_ptr(value)
  if value.is_a?(String)
    cptr = Pointer.malloc(value.bytesize)
    cptr.ffi_ptr.put_string(0, value)
    cptr

  elsif value.is_a?(Array)
    raise NotImplementedError, "array ptr"

  elsif value.respond_to?(:to_ptr)
    ptr = value.to_ptr
    case ptr
    when Pointer
      ptr
    when FFI::Pointer
      Pointer.new(ptr)
    else
      raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{ptr.class}")
    end

  else
    Pointer.new(value)
  end
end
也别名为: []
write(addr, bytes) 点击切换源代码

str 中的字节写入到 address 指向的位置。

# File fiddle/lib/fiddle/ffi_backend.rb, line 265
def self.write(addr, bytes)
  FFI::Pointer.new(addr).write_bytes(bytes)
end

公共实例方法

+(delta) 点击切换源代码

返回一个新的指针实例,该实例已前进 n 个字节。

# File fiddle/lib/fiddle/ffi_backend.rb, line 440
def +(delta)
  self.class.new(to_i + delta, @size - delta)
end
+@() 点击切换源代码

返回一个新的 Fiddle::Pointer 实例,它是此指针的解引用指针。

类似于 C 中的星号运算符。

# File fiddle/lib/fiddle/ffi_backend.rb, line 468
def +@
  ptr
end
-(delta) 点击切换源代码

返回一个新的指针实例,该实例已后退 n 个字节。

# File fiddle/lib/fiddle/ffi_backend.rb, line 444
def -(delta)
  self.class.new(to_i - delta, @size + delta)
end
-@() 点击切换源代码

返回一个新的 Fiddle::Pointer 实例,它是此指针的引用指针。

类似于 C 中的 & 运算符。

# File fiddle/lib/fiddle/ffi_backend.rb, line 472
def -@
  ref
end
<=>(other) 点击切换源代码

如果小于,则返回 -1;如果等于,则返回 0;如果大于 other,则返回 1。

如果无法将 ptrother 进行比较,则返回 nil。

# File fiddle/lib/fiddle/ffi_backend.rb, line 448
def <=>(other)
  return unless other.is_a?(Pointer)
  diff = self.to_i - other.to_i
  return 0 if diff == 0
  diff > 0 ? 1 : -1
end
==(other) 点击切换源代码

如果 other 包装相同的指针,则返回 true,否则返回 false。

# File fiddle/lib/fiddle/ffi_backend.rb, line 460
def ==(other)
  eql?(other)
end
[](index, length = nil) 点击切换源代码

返回存储在 index 处的整数。

如果给定了 startlength,则返回包含从 start 开始的 length 字节的字符串。

# File fiddle/lib/fiddle/ffi_backend.rb, line 396
def [](index, length = nil)
  if length
    ffi_ptr.get_bytes(index, length)
  else
    ffi_ptr.get_char(index)
  end
rescue FFI::NullPointerError
  raise DLError.new("NULL pointer dereference")
end
[]=(*args, value) 点击切换源代码

index 处的值设置为 int

或者,使用 string 的内容、dl_cptr 的内存或内存地址 addr 指向的内存,设置从 startlength 的内存。

# File fiddle/lib/fiddle/ffi_backend.rb, line 277
def []=(*args, value)
  if args.size == 2
    if value.is_a?(Integer)
      value = self.class.new(value)
    end
    if value.is_a?(Fiddle::Pointer)
      value = value.to_str(args[1])
    end

    @ffi_ptr.put_bytes(args[0], value, 0, args[1])
  elsif args.size == 1
    if value.is_a?(Fiddle::Pointer)
      value = value.to_str(args[0] + 1)
    else
      value = value.chr
    end

    @ffi_ptr.put_bytes(args[0], value, 0, 1)
  end
rescue FFI::NullPointerError
  raise DLError.new("NULL pointer access")
end
call_free() 点击切换源代码

为此指针调用释放函数。多次调用不会执行任何操作。如果没有附加释放函数,则不执行任何操作。

# File fiddle/lib/fiddle/ffi_backend.rb, line 377
def call_free
  return if @free.nil?
  return if @freed
  if @free == RUBY_FREE
    LibC::FREE.call(@ffi_ptr)
  else
    @free.call(@ffi_ptr)
  end
  @freed = true
end
eql?(other) 点击切换源代码

如果 other 包装相同的指针,则返回 true,否则返回 false。

# File fiddle/lib/fiddle/ffi_backend.rb, line 455
def eql?(other)
  return unless other.is_a?(Pointer)
  self.to_i == other.to_i
end
free() 点击切换源代码

获取此指针的释放函数。

返回 Fiddle::Function 的新实例。

请参阅 Fiddle::Function.new

# File fiddle/lib/fiddle/ffi_backend.rb, line 369
def free
  @free
end
free=(free) 点击切换源代码

将此指针的释放函数设置为给定的 Fiddle::Function 中的 function

# File fiddle/lib/fiddle/ffi_backend.rb, line 373
def free=(free)
  @free = free
end
freed?() 点击切换源代码

如果此指针的释放函数已被调用,则返回 true。

# File fiddle/lib/fiddle/ffi_backend.rb, line 388
def freed?
  @freed
end
inspect() 点击切换源代码

返回一个格式化的字符串,其中包含指针内部状态的易于阅读的表示形式。

# File fiddle/lib/fiddle/ffi_backend.rb, line 436
def inspect
  "#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>"
end
null?() 点击切换源代码

如果这是一个空指针,则返回 true

# File fiddle/lib/fiddle/ffi_backend.rb, line 357
def null?
  @ffi_ptr.null?
end
ptr() 点击切换源代码

返回一个新的 Fiddle::Pointer 实例,它是此指针的解引用指针。

类似于 C 中的星号运算符。

# File fiddle/lib/fiddle/ffi_backend.rb, line 464
def ptr
  Pointer.new(ffi_ptr.get_pointer(0))
end
ref() 点击切换源代码

返回一个新的 Fiddle::Pointer 实例,它是此指针的引用指针。

类似于 C 中的 & 运算符。

# File fiddle/lib/fiddle/ffi_backend.rb, line 476
def ref
  cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE)
  cptr.ffi_ptr.put_pointer(0, ffi_ptr)
  cptr
end
size() 点击切换源代码

获取此指针的大小。

# File fiddle/lib/fiddle/ffi_backend.rb, line 365
def size
  defined?(@layout) ? @layout.size : @size
end
size=(size) 点击切换源代码

将此指针的大小设置为 size

# File fiddle/lib/fiddle/ffi_backend.rb, line 392
def size=(size)
  @size = size
end
to_i() 点击切换源代码

返回此指针的整数内存位置。

# File fiddle/lib/fiddle/ffi_backend.rb, line 406
def to_i
  ffi_ptr.to_i
end
也别名为: to_int
to_int()

返回此指针的整数内存位置。

别名为: to_i
to_ptr() 点击切换源代码
# File fiddle/lib/fiddle/ffi_backend.rb, line 361
def to_ptr
  @ffi_ptr
end
to_s(len = nil) 点击切换源代码

不带 0

# File fiddle/lib/fiddle/ffi_backend.rb, line 412
def to_s(len = nil)
  if len
    ffi_ptr.get_string(0, len)
  else
    ffi_ptr.get_string(0)
  end
rescue FFI::NullPointerError
  raise DLError.new("NULL pointer access")
end
to_str(len = nil) 点击切换源代码

以字符串形式返回指针内容。

当不带参数调用时,此方法将返回长度为此指针的 size 的内容。

当使用 len 调用时,将返回 len 字节的字符串。

请参阅 to_s

# File fiddle/lib/fiddle/ffi_backend.rb, line 422
def to_str(len = nil)
  if len
    ffi_ptr.read_string(len)
  else
    ffi_ptr.read_string(@size)
  end
rescue FFI::NullPointerError
  raise DLError.new("NULL pointer access")
end
to_value() 点击切换源代码

将此指针转换为 ruby 对象。

# File fiddle/lib/fiddle/ffi_backend.rb, line 432
def to_value
  raise NotImplementedError, "to_value isn't supported"
end