A Scheme value is represented by a pointer-size value. The low bit is a mark bit: a 1 in the low bit indicates an immediate integer, a 0 indicates a (word-aligned) pointer.
A pointer-based Scheme value references a structure that begins with a type tag. This type tag has the C type Scheme_Type. The rest of the structure (following the type tag) is type-dependent. Examples of Scheme_Type values include scheme_pair_type, scheme_symbol_type, and scheme_compiled_closure_type.
MzScheme's C interface gives Scheme values the type Scheme_Object *. (The ``object'' here does not refer to objects in the sense of object-oriented programming.) The struct type Scheme_Object is defined in scheme.h, but never access this structure directly. Instead, use macros (such as SCHEME_CAR) that provide access to the data of common Scheme types. A Scheme_Object structure is actually only allocated for certain types (a few built-in types that contain two words of data in addition to the type tag), but Scheme_Object * is nevertheless used as the type of a generic Scheme value (for historical reasons).
For all standard Scheme types, constructors are provided for creating Scheme values. For example, scheme_make_pair takes two Scheme_Object * values and returns the cons of the values.
The macro SCHEME_TYPE takes a Scheme_Object * and returns the type of the object. This macro performs the tag-bit check, and returns scheme_integer_type when the value is an immediate integer; otherwise, SCHEME_TYPE follows the pointer to get the type tag. Macros are provided to test for common Scheme types; for example, SCHEME_PAIRP returns 1 if the value is a Scheme cons cell, 0 otherwise.
In addition to the standard Scheme data types, there are six global constant Scheme values: scheme_true, scheme_false, scheme_null, scheme_eof, scheme_void, and scheme_undefined. Each of these has a unique type tag, but they are normally recognized via their constant addresses rather than via their type tags.
An extension or application can create new a primitive data type by calling scheme_make_type, which returns a fresh Scheme_Type value. To create a collectable instance of this type, allocate memory for the instance with scheme_malloc. From MzScheme's perspective, the only constraint on the data format of such an instance is that the first sizeof(Scheme_Type) bytes must contain the value returned by scheme_make_type.
Scheme values should never be allocated on the stack, or contain pointers to values on the stack. Besides the problem of restricting the value's lifetime to that of the stack frame, allocating values on the stack creates problems for continuations and threads, both of which copy into and out of the stack.