Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ffi.pointer

import ffi.pointer

ffi lifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelled ffi.pointer.* needs import ffi.pointer.

Addresses in native memory, and reading and writing through them.

A Pointer is an address with, optionally, the type of what it points at. The type is what get(), set() and the field methods read and write, and the unit add() steps by; read() and write() take a type of their own and work on any pointer.

Memory this module allocated knows its own extent, and every access through a pointer into it is checked against that extent and against the memory having been freed. A pointer C handed back carries no extent, so only a null pointer is caught; reading past what the C library says is there is as undefined as it is in C.

Classes

Pointer

class ffi.Pointer

An address in native memory.

Pointers come from ffi.alloc() and its siblings, from functions that return one, and from reading a pointer out of memory. A null pointer returned from C arrives as nil instead, so if ptr is how a program checks for one.

Memory from ffi.alloc() is freed when the last pointer into it is collected. Keep a pointer reachable for as long as C code holds the address.

  • printable — has a @to_string(), so echo and print() show something useful

Constructor

ffi.Pointer()

Pointer.address()

ffi.Pointer.address() -> number|bigint

The address, as a number, or as a bigint where it is too large for a number to hold exactly.

Returns number|bigint

Pointer.is_null()

ffi.Pointer.is_null() -> bool

Whether the address is zero. A null pointer only exists as the result of arithmetic or ffi.at(0); C returning one gives nil.

Returns bool

Pointer.type()

ffi.Pointer.type() -> Type|nil

The type of what the pointer points at, or nil for an untyped pointer such as ffi.alloc_bytes() returns.

Returns Type|nil

Pointer.cast()

ffi.Pointer.cast(type) -> Pointer

The same address, pointing at type instead. Bounds and ownership carry over. Pass nil for an untyped pointer.

Parameters

  • type (Type|nil)

Returns Pointer

Pointer.offset()

ffi.Pointer.offset(bytes) -> Pointer

The pointer bytes further on, negative for back. Keeps the type.

Parameters

  • bytes (number)

Returns Pointer

Pointer.add()

ffi.Pointer.add(count) -> Pointer

The pointer count elements further on, as C’s ptr + count is.

Parameters

  • count (number) — Negative steps back.

Returns Pointer

Raises TypeError when the pointer has no element type, or its element type has no size.

Pointer.size()

ffi.Pointer.size() -> number|nil

How many bytes are known to be addressable from here to the end of the block, or nil when the extent is unknown, as it is for any pointer C handed back.

Returns number|nil

Pointer.read()

ffi.Pointer.read(type, offset) -> any

Reads a value of type at offset bytes from the pointer.

var header = ffi.alloc_bytes(16)
var magic = header.read(ffi.uint32)
var length = header.read(ffi.uint64, 8)

Parameters

  • type (Type)
  • offset (number|nil) — Defaults to 0.

Returns any

Raises PointerError when the pointer is null, the memory is freed, or the read runs outside a known block.

Pointer.write()

ffi.Pointer.write(type, value, offset)

Writes value as type at offset bytes from the pointer.

Nothing is written when the value does not convert, so a failed write never leaves half a value behind. Writing a record or array as a whole replaces every member; members the value leaves out keep what they held.

Parameters

  • type (Type)
  • value (any)
  • offset (number|nil) — Defaults to 0.

Raises PointerError for the reasons read() does.

Raises TypeError when value cannot be stored as type.

Raises RangeError when a number does not fit type.

Pointer.get()

ffi.Pointer.get(index) -> any

Reads element index of the pointer’s type, as C’s ptr[index].

Parameters

  • index (number|nil) — Defaults to 0.

Returns any

Raises TypeError when the pointer has no element type.

Raises PointerError for the reasons read() does.

Pointer.set()

ffi.Pointer.set(index, value)

Writes element index of the pointer’s type, as C’s ptr[index] = value.

Parameters

  • index (number)
  • value (any)

Raises TypeError when the pointer has no element type or the value does not convert.

Raises PointerError for the reasons read() does.

Pointer.get_field()

ffi.Pointer.get_field(name) -> any

Reads one member of the struct or union the pointer points at, as C’s ptr->name. Bitfields read like any other member.

Parameters

  • name (string)

Returns any

Raises TypeError when the pointer does not point at a record.

Raises ValueError when the record has no such member.

Pointer.set_field()

ffi.Pointer.set_field(name, value)

Writes one member of the struct or union the pointer points at, as C’s ptr->name = value, leaving the other members alone.

Parameters

  • name (string)
  • value (any)

Raises TypeError when the pointer does not point at a record, or the value does not convert.

Raises ValueError when the record has no such member.

Raises RangeError when a number does not fit, including a bitfield’s width.

Pointer.field()

ffi.Pointer.field(name) -> Pointer

A pointer to one member, typed as the member, as C’s &ptr->name. Reaching into nested records is a chain of these.

An array member gives a pointer to its first element instead, typed as the element, as the member itself decays to in C. That is how a flexible array member’s elements are reached.

Parameters

  • name (string)

Returns Pointer

Raises TypeError for a bitfield, which has no address.

Pointer.read_string()

ffi.Pointer.read_string(length, encoding, offset) -> string

Reads text.

With a length, exactly that many code units; without one, up to the first zero code unit, which must lie within the block when the block’s extent is known.

Parameters

  • length (number|nil) — In code units, not bytes.
  • encoding (string|nil) — 'utf-8' (the default), 'utf-16', 'utf-32', or 'wide' for wchar_t, which is UTF-16 on Windows and UTF-32 elsewhere.
  • offset (number|nil) — In bytes. Defaults to 0.

Returns string

Raises ValueError when the text is not valid in its encoding.

Raises PointerError when there is no terminator inside a known block.

Pointer.write_string()

ffi.Pointer.write_string(text, encoding, offset) -> number

Writes text and a terminating zero, returning the bytes written.

Parameters

  • text (string)
  • encoding (string|nil) — As for read_string().
  • offset (number|nil) — In bytes. Defaults to 0.

Returns number

Raises PointerError when the text and terminator do not fit a known block.

Pointer.read_bytes()

ffi.Pointer.read_bytes(length, offset) -> bytes

Copies length bytes out.

Parameters

  • length (number)
  • offset (number|nil) — Defaults to 0.

Returns bytes

Pointer.write_bytes()

ffi.Pointer.write_bytes(data, offset) -> number

Copies data in, returning how many bytes were written.

Parameters

  • data (bytes)
  • offset (number|nil) — Defaults to 0.

Returns number

Pointer.to_list()

ffi.Pointer.to_list(count) -> list

Reads count elements of the pointer’s type into a list.

Parameters

  • count (number)

Returns list

Pointer.copy_from()

ffi.Pointer.copy_from(source, length)

Copies length bytes from source, a pointer or bytes, to here. The two ranges may overlap.

Parameters

  • source (Pointer|bytes)
  • length (number)

Pointer.fill()

ffi.Pointer.fill(byte, length)

Sets length bytes to byte.

Parameters

  • byte (number) — 0 to 255.
  • length (number)

Pointer.compare()

ffi.Pointer.compare(other, length) -> number

Compares length bytes here with length bytes at other, as memcmp does: -1, 0 or 1.

Parameters

  • other (Pointer)
  • length (number)

Returns number

Pointer.own()

ffi.Pointer.own(destructor)

Takes ownership of memory C allocated, so it is released when the pointer is collected.

destructor is the C function that releases it, taking the address as its one argument. Leave it out for memory from the C allocator, which free releases. Pointers derived from this one afterwards share the ownership.

A destructor run by the collector cannot call back into Zuri: any callback it calls returns zero to C, or its error_value. free() runs the destructor with callbacks working as usual.

var text = c.strdup('hello').own()
var db = sqlite.open_handle(path).own(sqlite.sqlite3_close)

Parameters

  • destructor (function|nil) — A foreign function of one pointer.

Returns — self

Raises PointerError when the pointer is null or already owned.

Raises TypeError when the destructor is not a foreign function of one pointer.

Pointer.free()

ffi.Pointer.free()

Releases owned memory now rather than when it is collected: memory from ffi.alloc() or ffi.malloc(), or taken over with own(). Every pointer into it refuses access from then on.

Raises PointerError when the pointer does not own its memory, does not point at the start of it, or it has already been freed.

Pointer.is_freed()

ffi.Pointer.is_freed() -> bool

Whether the memory this pointer owns has been freed.

Returns bool

Pointer.is_owned()

ffi.Pointer.is_owned() -> bool

Whether this pointer owns its memory: it came from ffi.alloc() or ffi.malloc(), or own() was called on it or a pointer it came from.

Returns bool

Pointer.equals()

ffi.Pointer.equals(other) -> bool

Whether other is a pointer to the same address.

Parameters

  • other (any)

Returns bool

Pointer.to_string()

ffi.Pointer.to_string()

2026, Richard Ore and Zuri contributors