The ANSI Standard indicates that integer constants (either literals or integer non-pointer variables) may be assigned to pointers, but what happens after that is implementation defined. That is to say, it is not clear what will happen if you dereference the pointer or perform other operations on it.
You will also notice in the Standard that pointers are only considered valid when they point to an object. You can be guaranteed that a pointer points to an object if you assign it the address of an object (using the unary & operator) rather than assigning an integer value.
The MPLAB® XC8 compilers perform a number of optimizations that are based on information obtained from each pointer's target list. These optimizations can be defeated if the information regarding targets is not complete.
Regardless of which compiler you use, always take the address of an object when assigning to a pointer. In some instances it may be necessary to create a dummy object whose address can be taken, if no other object exists.
The information the compiler needs to fully understand a pointer target is:
- the base address of the target
- the size of the target
- the memory space in which the target lies; and
- the type of the target
Let's look at special examples where you might be tempted to assign integers to pointers.
Let's say you want to use a pointer to calculate a checksum of all locations in bank 2 data memory (from addresses 110h to 16fh) on a mid-range PIC® device. We assume here that every memory location holds a significant value, but that there could be many C objects that reside in bank 2, and we are not sure which object these are. First create a dummy object which does reside at the addresses of interest and in the desired memory space:
The object is made extern so that it does not have memory reserved for it, and being absolute, it can exist "over the top" of other objects in this bank. From this object the compiler can determine all four of the above attributes. Now you can use this object:
Note the pointer is assigned an address which is derived from a C object.
Note also the pointer comparison in the while() statement. The ANSI standard also indicates that addresses may only be compared when they point to the same object. Again, you should compare pointers with the address of some object, not an integer constant cast to be a pointer.
If you wanted to do a similar thing, but with objects in program memory, the procedure is the same. Note that not all devices can directly read their own program memory, and may implement program memory which is word-addressable. If arrays are located in this memory, the values read using a pointer will be the data values in the array. You could not use this method to calculate a checksum of the instructions in a block of program memory. You would need to use flash read function to do that, if they exist for the target device.
Let's say we want to read from address 2000h to 2fffh, and assuming there is no single C object that resides at these addresses, first create a dummy object which is located here and in the desired memory space:
Here the const qualifier implies the program memory space. As there is no initial values, this object does not contribute to the output hex file and so will not overwrite any other objects.
Now you can use this object:
The Compiler does understand the special case of an assignment of 0 (zero) to a pointer. This is a null pointer, has special meaning, and is an address that is guaranteed not to point to any object.
If you need to take the address of an object defined in assembly code, then write an appropriate C declaration for the assembly object, then use this C object as the target.