3.3 Pointer dereferencing and coercing

The dereference function returns the value stored at the location held by a pointer, provided the type of the object is an immediate type and not a structure or an aggregate type. For now, you can consider immediate data types to be the simple types such as :int, :byte, and :char, and aggregate types to consist of structures defined using
:struct
. Full details about types are given in FLI Types, and the use of the dereference function with aggregate types is discussed further in Advanced Uses of the FLI.

The dereference function supports the
setf
function which can therefore be used to set values at the address pointed to by the pointer. In the following example an integer is allocated and a pointer to the integer is returned. Then dereference and
setf
are used to set the value of the integer to
12
. Finally, the value of the integer is returned using
fli:dereference
.

The function dereference has an optional
:type
keyword which can be used to return the value pointed to by a pointer as a different type. This is known as coercing a pointer. The default value for
:type
is the type the pointer is specified as pointing to. In the next example the value at
point5
is returned as a Lisp boolean even thought it was set as an
:int
. Because the value at
point5
is not 0, it is returned as
t
.

(fli:dereference point5 :type '(:boolean :int))

Recall that at the end of the previous section the function pointer-element-type was demonstrated. What follows is an example which uses this function to clarify the issue of pointers and types.

The first action consists of allocating an integer, and setting up a pointer to this integer:

(setq pointer-a (fli:allocate-foreign-object :type :int))

Now we use
fli:copy-pointer
to make a copy of
pointer-a
, but with the type of the new pointer changed to be a
:byte
. We call this pointer
pointer-b
.

(setq pointer-b (fli:copy-pointer pointer-a :type :byte))

We now have two pointers which point to the same memory location, but one thinks it is pointing to an
:int
, and the other thinks it is pointing to a
:byte
. Test this by using the following two commands:

Similar commands using pointer-element-size show that
pointer-a
is pointing to an element of size 4, and
pointer-b
to an element of size 1.

So far we have seen the use of the
:type
keyword to specify how to set up or dereference a pointer to obtain values in the format we want. There is, however, a further level of abstraction in pointer typing which uses the
:pointer-type
keyword instead of the
:type
keyword.

The following two commands produce identical pointers, but one uses the
:type
keyword, and the other uses the
:pointer-type
keyword:

In the instance above there is no advantage in using the
:pointer-type
option. However,
:pointer-type
can be very useful when used in combination with a defined type, as the next example shows.

Imagine you are writing a program with many statements creating pointers to a certain type, for example
:byte
, and this is done using the
:type
keyword. If half way through coding the type to be pointed to was changed to a
:char
, every individual statement would need to be changed. However, if a general pointer type had been defined at the start and all the statements had used the
:pointer-type
keyword to refer to that particular type, only one statement would need to be changed: the initial definition of the pointer type. The following code illustrates this:

(fli:define-c-typedef my-pointer-type (:pointer :byte))

(fli:make-pointer :address 0 :pointer-type 'my-pointer-type)

...

(fli:make-pointer :address 100 :pointer-type 'my-pointer-type)

The above code consists of a definition of a new pointer type, called
my-pointer-type
, which points to a
:byte
. Following it are one hundred lines of code using
my-pointer-type
. If you decide that all the pointers made should actually point to a
:char
, only the first line needs to be changed, as shown below:

(fli:define-c-typedef my-point-type (:pointer :char))

The program can now be re-compiled. The use of
:pointer-type
with pointers is thus analogous to the use of constants instead of absolute numbers in programming.