1.1 Machine Addresses
Felix provides some types which are used to manipulate machine addresses and memory at a low level.
The type address
is basically a C void*
.
However, you can add or subtract an integer from an address,
as if it were actually a C unsigned char*
, and of course
you can also just increment or decrement an addess.
Addition of an integer to an address is modular, that is, the addition may cause wrap around like an unsigned integer type.
Addresses are totally ordered and support the usual comparisons however addition is not confluent with comparisons:
x > y does not imply x + 1 > y + 1
You can also subtract two addresses, the result is of type ptrdiff
.
This is a signed integer type with the same number of values as
there are addresses. If the addresses are close and the first address
is larger than the second the result is positive, negative if they're
ordered the other way. If the addresses are a long way apart, in particular
more than half the total number of addres value distant, then the difference
goes through the maximum value to the zero value and the sign is the
opposite of what is expected. In particular the absolute value
of the difference is the shortest distance between the addresses
around the address circle.
Therefore, the difference operation is also not confluent with comparisons, that is,
x < y does not imply y - x > 0
In particular if x
is very small, and y
is very big then
whilst mathematically y-x > 0
, the ptrdiff
will instead be a
small negative value.
To solve this problem Felix also provides two more types:
intptr
and uintptr
which support the same number of values
as an address: intptr
is identical to ptrdiff
whereas
uintptr
is unsigned.
Casting a pointer difference to uintptr
is confluent with comparisons.
If y > x
then (y-x).uintptr
is precisely the mathematical value
of the difference. If the pointers are reversed the value is the mathematical
result (which is negative) added to the number of values (one more than the
maximum).
Addresses cannot be dereferenced.
An address can be obtained from any pointer or integer. You can also cast an address to any pointer type, the onus is on you, the programmer, to ensure the address actually pointers to store containing a value of that type.
The type
&byte
supports the same operations as an address except it can be dereferenced.