Dereferencing Typecast Integer Literals

Doug Gwyn gwyn at smoke.brl.mil
Tue Feb 5 03:53:22 AEST 1991


In article <22700 at netcom.UUCP> avery at netcom.UUCP (Avery Colter) writes:
>Now, obviously, in C, the most obvious way to do any of these is to declare
>a char pointer. Dereferencing this pointer as an r-value PEEKs, dereferencing
>it as an l-value POKEs, and dereferencing it with a parameter list postfixed
>CALLs.

In some implementations the latter is not supported, and the specific
integral type needed to hold a data "address" for such usage is
implementation dependent.  (So be careful!)

>However..... since all pointer objects are pseudo-integer in nature, and since
>they are considered to be typecast cousins of the true integers, my question
>is whether it is necessary to even declare a pointer for these tasks.

I don't understand that at all.  In C, each object consists of one or
more bytes, and within (also "one past") an object a linear address
space model is assumed.  Also, each implementation is required to
provide SOME integral type to which any data pointer can be cast such
that upon subsequent cast back to the same type of pointer, the new
pointer value will compare equal to the old value.  This may actually
involve some weird run-time implementation of "pointer equivalence
classes", depending on what the machine architecture is like.

>1. Since a constant literal integer of the appropriate size for the
>implementation can be typecast into a pointer to any type, is it then 
>possible to dereference the result of this typecast expression?

The major premise is false.  It is NOT required that an arbitrary
integral value be convertable to an object pointer, only that some
suitable representation as an integer (of the implementation-dependent
type) exist for each object pointer that is valid in the higher-level
C abstract-machine model.  In particular, there may be a range of
"addresses" that are completely inaccessible from a C program; this is
usually the case for virtual-memory operating systems and others that
have separate physical address spaces for user versus supervisor tasks.
Also, even if the memory is accessible from C, you have to obey object
alignment constraints; for example, full-word accesses may require that
the integer representation be a number that is exactly divisible by 2
or by 4.

>s = *(char *)0xC000; /* C000: address of the keyboard strobe on Apple II */

On most Apple II C compilers, this would indeed pick up the data at that
"soft switch" location.  You need to be aware that in some cases (although
not likely in this case) the compiler can generate multiple accesses to
the location even though you have specified it only once in the source
code.  For I/O registers, including Apple II soft switches, there are
often side effects from an access, such as clearing a flip-flop, and many
locations behave differently for read versus write access.  ANSI C has
introduced the "volatile" type qualifier to provide a handle for the C
programmer to try to obtain as near to a one-to-one mapping between the
explicit source code and the generated machine instructions as possible;
in older C implementations one simply had to be aware of what code would
be generated for certain C constructs and then make sure that the proper
constructs were used to obtain the desired effect.  It is still highly
recommended that you inspect the generated code to make sure that you are
getting the desired effect.

>2. If #1 can be done, then can a dereferenced typecast integer constant
>be used as an l-value?
>*(char *)0xC010 = 0; /* C010: value zeroed to signal ready to take another
>			  character into C000 			    */

Sure, why not?  Once the integer has been converted to a pointer, you are
back in the domain of standard C.

>3. Can a DTIC have a parameter list postfixed to make it into a function
>call?

There is no guarantee that this will work, although some implementations
will support it.

>*(void (*()))0xFC58();  /* FC58: address of firmware HOME function */

This, however, is not syntactically correct.  You should instead try
	((void (*)())0xFC58)();
or if your compiler is brain-damaged
	(*(void (*)())0xFC58)();

>What's the consensus on all this? Is it better to just declare const
>pointer objects for all the firmware points you wish to have on hand?

Recommended practice is to define macros for such accesses, using yet
other macros that implement generic access of a certain type.  E.g.

	#define PEEK(addr,type) (*((type)*)(addr))
	#define	KBDSTROBE PEEK(0xC000,char)



More information about the Comp.lang.c mailing list