类 Fiddle::Pointer
Fiddle::Pointer
是一个用于处理 C 指针的类
属性
公共类方法
# File fiddle/lib/fiddle/ffi_backend.rb, line 236 def self.from_native(value, ctx) self.new(value) end
示例¶ ↑
# 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
# 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
创建一个指向 address
的新指针,带有可选的 size
和 freefunc
。
当实例被垃圾回收时,将调用 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; }
或者读取地址 address
处长度为 len
的内存,并返回包含该内存的字符串
# File fiddle/lib/fiddle/ffi_backend.rb, line 269 def self.read(addr, len) FFI::Pointer.new(addr).read_bytes(len) end
# 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
获取 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
将 str
中的字节写入到 address
指向的位置。
# File fiddle/lib/fiddle/ffi_backend.rb, line 265 def self.write(addr, bytes) FFI::Pointer.new(addr).write_bytes(bytes) end
公共实例方法
返回一个新的指针实例,该实例已前进 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
返回一个新的指针实例,该实例已后退 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
如果小于,则返回 -1;如果等于,则返回 0;如果大于 other
,则返回 1。
如果无法将 ptr
与 other
进行比较,则返回 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
包装相同的指针,则返回 true,否则返回 false。
# File fiddle/lib/fiddle/ffi_backend.rb, line 460 def ==(other) eql?(other) end
返回存储在 index 处的整数。
如果给定了 start 和 length,则返回包含从 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
将 index
处的值设置为 int
。
或者,使用 string
的内容、dl_cptr
的内存或内存地址 addr
指向的内存,设置从 start
到 length
的内存。
# 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
为此指针调用释放函数。多次调用不会执行任何操作。如果没有附加释放函数,则不执行任何操作。
# 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
如果 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
获取此指针的释放函数。
返回 Fiddle::Function
的新实例。
# File fiddle/lib/fiddle/ffi_backend.rb, line 369 def free @free end
将此指针的释放函数设置为给定的 Fiddle::Function
中的 function
。
# File fiddle/lib/fiddle/ffi_backend.rb, line 373 def free=(free) @free = free end
如果此指针的释放函数已被调用,则返回 true。
# File fiddle/lib/fiddle/ffi_backend.rb, line 388 def freed? @freed end
返回一个格式化的字符串,其中包含指针内部状态的易于阅读的表示形式。
# 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
如果这是一个空指针,则返回 true
。
# File fiddle/lib/fiddle/ffi_backend.rb, line 357 def null? @ffi_ptr.null? end
返回一个新的 Fiddle::Pointer
实例,它是此指针的解引用指针。
类似于 C 中的星号运算符。
# File fiddle/lib/fiddle/ffi_backend.rb, line 464 def ptr Pointer.new(ffi_ptr.get_pointer(0)) end
返回一个新的 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
获取此指针的大小。
# File fiddle/lib/fiddle/ffi_backend.rb, line 365 def size defined?(@layout) ? @layout.size : @size end
将此指针的大小设置为 size
# File fiddle/lib/fiddle/ffi_backend.rb, line 392 def size=(size) @size = size end
返回此指针的整数内存位置。
# File fiddle/lib/fiddle/ffi_backend.rb, line 406 def to_i ffi_ptr.to_i end
# File fiddle/lib/fiddle/ffi_backend.rb, line 361 def to_ptr @ffi_ptr end
不带 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
以字符串形式返回指针内容。
当不带参数调用时,此方法将返回长度为此指针的 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
将此指针转换为 ruby 对象。
# File fiddle/lib/fiddle/ffi_backend.rb, line 432 def to_value raise NotImplementedError, "to_value isn't supported" end