struct

A struct declaration inside a lib declares a C struct.

lib C
  # In C:
  #
  #  struct TimeZone {
  #    int minutes_west;
  #    int dst_time;
  #  };
  struct TimeZone
    minutes_west : Int32
    dst_time : Int32
  end
end

You can also specify many fields of the same type:

lib C
  struct TimeZone
    minutes_west, dst_time : Int32
  end
end

Recursive structs work just like you expect them to:

lib C
  struct LinkedListNode
    prev, _next : LinkedListNode*
  end

  struct LinkedList
    head : LinkedListNode*
  end
end

To create an instance of a struct use new:

tz = C::TimeZone.new

This allocates the struct on the stack.

A C struct starts with all its fields set to "zero": integers and floats start at zero, pointers start with an address of zero, etc.

To avoid this initialization you can use uninitialized:

tz = uninitialized C::TimeZone
tz.minutes_west # => some garbage value

You can set and get its properties:

tz = C::TimeZone.new
tz.minutes_west = 1
tz.minutes_west # => 1

If the assigned value is not exactly the same as the property's type, to_unsafe will be tried.

You can also initialize some fields with a syntax similar to named arguments:

tz = C::TimeZone.new minutes_west: 1, dst_time: 2
tz.minutes_west # => 1
tz.dst_time     # => 2

A C struct is passed by value (as a copy) to functions and methods, and also passed by value when it is returned from a method:

def change_it(tz)
  tz.minutes_west = 1
end

tz = C::TimeZone.new
change_it tz
tz.minutes_west # => 0

Refer to the type grammar for the notation used in struct field types.

To the extent possible under law, the persons who contributed to this workhave waived
all copyright and related or neighboring rights to this workby associating CC0 with it.
https://crystal-lang.org/reference/syntax_and_semantics/c_bindings/struct.html