[net.lang.c] Casting Question

chinn@butler.UUCP (David Chinn) (01/14/86)

*** REPLACE THIS LINE WITH YOUR MESSAGE ***
I have been looking at hoc, which appeared on the net
some time ago.  I am relatively new to the language (C)
and so was puzzled by the following ....


typedef int (*Inst)();  /* machine instruction */
			/* Inst is typedefed to a "pointer to a function
			   returning an integer */
	.

Inst    *pc;            /* program counter during execution */
			/* pc is declared to be a pointer to an Inst;
	.	           or, a pointer to a pointer to a function  */
		
ifcode()
{
	Inst *savepc= pc;     /* then part */
			      /* savepc is the same as pc */

        	pc = *((Inst **)(savepc+2));     /* next stmt */
                     ^^^^^^^^^^^^^^^^^^^^^^
                      So what is this for?

}

I understand that the cast makes it (savepc+2) a pointer to a pointer to
an Inst (or a pointer to a pointer to a pointer to a function returning
an integer).  But then the de-referencing star on the outside takes one
level of indirection away, making savepc+2 what it was anyway ( a
pointer to a pointer to a function returning an integer.)

I compiled hoc and tested the if statement; it worked.  I edited code.c
and removed the seemingly extraneous cast and de-ref: it still worked.

Any enlightenment would be appreciated....

    ... uw-beaver                                david m chinn
           !{tikal,teltone}                      box 2249
	       !dataio!butler!chinn     	 kirkland, wash 98083

gwyn@BRL.ARPA (VLD/VMB) (01/17/86)

pc = *((Inst **)(savepc+2));
is not the same as
pc = (Inst *)(savepc+2);
In the former case, you are saying that savepc+2 points at an
(Inst *), which you retrieve and stuff into pc.  In the latter
case, you are setting pc to be equal to the pointer savepc+2.
Not at all the same thing.

Figuring out how this section of hoc works is great C practice.

thomas@utah-gr.UUCP (Spencer W. Thomas) (01/18/86)

In article <162@butler.UUCP> chinn@butler.UUCP (David Chinn) writes:
>Inst    *pc;            /* program counter during execution */
>			/* pc is declared to be a pointer to an Inst;
>	.	           or, a pointer to a pointer to a function  */

>        	pc = *((Inst **)(savepc+2));     /* next stmt */
>                     ^^^^^^^^^^^^^^^^^^^^^^
>                      So what is this for?
What appears to be happening here is that the location savepc+2 is a
POINTER to a location containing the desired pc value.  Certainly
(in this case) removing the cast will not affect the code (you are still
dereferencing savepc+2, and the value there is still a pointer), but the
types on the left and right of the assignment DO NOT MATCH!  If you run
lint over the code, it will complain.  The right hand side of the
assignment will be an Inst, while the left side is an Inst *.  The cast
keeps the types right.


-- 
=Spencer   ({ihnp4,decvax}!utah-cs!thomas, thomas@utah-cs.ARPA)
	"Ask not what your kernel can do for you, but rather what you
	 can do for you kernel!"

throopw@dg_rtp.UUCP (01/20/86)

> I am relatively new to the language (C) and so was puzzled by the
> following ....
>    typedef int (*Inst)();
>    Inst    *pc;
>    ifcode() {
>        Inst *savepc= pc;
>        pc = *((Inst **)(savepc+2));
>    }
> I understand that the cast makes it (savepc+2) a pointer to a pointer to
> an Inst (or a pointer to a pointer to a pointer to a function returning
> an integer).  But then the de-referencing star on the outside takes one
> level of indirection away, making savepc+2 what it was anyway ( a
> pointer to a pointer to a function returning an integer.)

Yes and no.  Mostly no.  It makes it the same *type* it was before, but
the *meaning* is completely different.  This is a trick that was worried
over in net.lang.c some time before.  Actually, Inst *wants* to be
declared to be

            typedef Inst (*Inst)();
and used as
            pc = *(savepc+2);

but C doesn't allow this type of recursive definition.  The alternative
is to use "int" as a primitive type to "bottom out" the recursion, and
then use the cast to keep lint happy about assigning a pointer to a
function returning int to what wants to be a pointer to a pointer to a
function returning int.  Clear?  If not (and there is demand by mail) I
can repost some of the explaination that went by here a while back.

> I compiled hoc and tested the if statement; it worked.  I edited code.c
> and removed the seemingly extraneous cast and de-ref: it still worked.

I am not surprised.  The statement

        pc = *((Inst **)(savepc+2));

implies the same bit-wise manipulation (on most machines) as

        pc = *(savepc+2);

But there is a crucial difference.  In the latter case, "pc" is being
assigned a pointer of the wrong type, and lint will complain.  In the
former case, the types match, and no complaint ensues (unless you have a
barbaric lint that complains about all pointer casts, as some seem to
do).

Now, why is the difference crucial?  Because on some machines, it may
conceiveably be important to have these types match correctly.
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!dg_rtp!throopw