[comp.lang.c] Do you have to cast void pointers when dereferencing them?

dmg@ssc-vax.UUCP (David Geary) (12/14/88)

  struct junk { int   x,y; };
  struct funk { float f,z; }; 

  main()
  {
    struct junk J;
    struct funk F;
    void  *p;

    J.x = 10,  J.y = 20;
    F.f = 4.2, F.z = 5.6;

    p = &J, printf("JUNK:  %d %d\n", p->x, p->y);

    p = &F, printf("FUNK:  %f %f\n", p->f, p->z);
}

  This runs just fine on my Sun, but gives me illegal
pointer WARNINGS.  Under ANSI C, do I HAVE to cast
my void pointer, or not?

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ David Geary, Boeing Aerospace,               ~ 
~ #define    Seattle     RAIN                  ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/15/88)

In article <2414@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
>  This runs just fine on my Sun, but gives me illegal
>pointer WARNINGS.  Under ANSI C, do I HAVE to cast
>my void pointer, or not?

Many older UNIX compilers will accept pointer to almost anything
in the context p->member_name, if the member_name has an unambiguous
structure offset.  Indeed, really old UNIX kernels (around 6th
Edition) relied heavily on this.

It's not currently legal to use anything other than a pointer to
a structure declared as having such a member_name in that context.
This applies even more strongly for void*, which has only a small
subset of permitted operations, definitely not including structure
member reference.

So, yes, write your code to say what you really mean.

chris@mimsy.UUCP (Chris Torek) (12/15/88)

In article <2414@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
[edited]
>struct junk { int   x,y; };
>    struct junk J;
>    void  *p;
>    p = &J;
>    ... p->x ...

The assignment `p = &J' (uncast) is legal dpANS C.  The reference
`p->x' is not.  To see why, consider this fragment:

	struct foople { char alpha, omega; } f;
	struct gluxet { int rho, omega; } g;
	void *p;
	if (flipcoin() == HEADS) p = &f; else p = &g;
	printf("%d\n", p->omega);

Which omega should be used?

(I used `if ... p = &f; else p = &g;' instead of `p = ... ? &f : &g;'
to avoid questions about mixing ?: pointer types, which, when last
I checked, seemed rather muddled.  The sensible approach is to make
`... ? &f : &g' illegal.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

henry@utzoo.uucp (Henry Spencer) (12/16/88)

In article <2414@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
>...  Under ANSI C, do I HAVE to cast
>my void pointer, or not?

Yes.  Deferencing a void pointer, whether directly via * or [] or more
obscurely via ->, is forbidden.

Many old compilers are quite sloppy about what they accept on the left
of the -> operator, but this has not been legitimate C for quite a while.
-- 
"God willing, we will return." |     Henry Spencer at U of Toronto Zoology
-Eugene Cernan, the Moon, 1972 | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

evil@arcturus.UUCP (Wade Guthrie) (12/17/88)

In article <15012@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> >    struct junk J;
> >    void  *p;
> >    p = &J;
> 
> The assignment `p = &J' (uncast) is legal dpANS C.  

Correct me if I'm wrong (on this net was THAT an unnecessary statement :-)),
but this seems to indicate that the dpANS performs implicit type
conversions for pointers.  

(To clarify my, often, imprecice terminology: given the following:

	int foo;
	float bar, fubar;

	fubar = foo + bar;

I call the cast of foo to a float (which is not done explicitly by the
programmer) along with the possible cast of both of these to double
(not necessarily in that order) an implicit type conversion)

My assumption (about the dbANS) comes from the understanding that
different pointers can have different representations (on some machines).
To say that pointer_of_one_type = pointer_of_another_type is legal, the
code must know the type of the lvalue to put the rvalue into the proper
representation.  Is this not true?


Wade Guthrie
Rockwell International
Anaheim, CA

(Rockwell doesn't necessarily believe / stand by what I'm saying; how could
they when *I* don't even know what I'm talking about???)

chris@mimsy.UUCP (Chris Torek) (12/18/88)

In article <3050@arcturus> evil@arcturus.UUCP (Wade Guthrie) writes:
>but this seems to indicate that the dpANS performs implicit type
>conversions for pointers.  

dpANS C does, but only for

	pointer to T => pointer to void

and

	pointer to void => pointer to T

where T is any type other than `pointer to void' (for which conversion
is unnecesssary) and perhaps `pointer to function returning T1'.  (It
is not entirely clear to me that the hack we used to allow

	char *pc; void *pv; pc = pv; pv = pc;

in 4BSD PCC is wrong, but it does also allow

	void *pv; int (*pfi)(); pv = pfi; pfi = pv;

and I am suspicious that this *is* wrong.)

>To say that pointer_of_one_type = pointer_of_another_type is legal, the
>code must know the type of the lvalue to put the rvalue into the proper
>representation.  Is this not true?

It is true.  But the compiler does indeed know both types.  In the
dpANS, if at least one of those types is `pointer to void' (and the
other provisos above hold true) the assignment is legal; otherwise,
such an assigment is legal only if the assignment is the result of a
cast: (pointer_of_one_type) pointer_of_another_type, e.g.,

	int i;
	(short *)&i

(remember that a cast is equivalent to assignment to an unnamed
temporary variable---I like to consider `assignment' to include all
casts).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guy@auspex.UUCP (Guy Harris) (12/18/88)

 >My assumption (about the dbANS) comes from the understanding that
 >different pointers can have different representations (on some machines).
 >To say that pointer_of_one_type = pointer_of_another_type is legal, the
 >code must know the type of the lvalue to put the rvalue into the proper
 >representation.  Is this not true?

Yes, it's true, and the compiler *does* know the type of the lvalue, so
it can generate code to do the implicit conversion properly.  Why is
this any different from

	int foo;
	float bar;

	bar = foo;

which also causes an implicit conversion from "int" to "float"?

evil@arcturus.UUCP (Wade Guthrie) (12/20/88)

In article <749@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes:

> Originally (well not ORIGINALLY. . .) I said:
>  >code must know the type of the lvalue to put the rvalue into the proper
>  >representation.  Is this not true?
> . . .Why is this any different from
> 	int foo; float bar; bar = foo;
> which also causes an implicit conversion from "int" to "float"?

The statement I made was regarding implicit conversion between pointer
types.  Well, as far as K&R goes, no implicit pointer type conversion
is made (they do describe how ints can be converted to float (actually
double, but I digress)).  This, I believe, is the root of some of the 
discussion lately that the following is non-portable:

	#define NULL (char *)0
	. . .
	int *foo;

	foo = NULL;

(note that different pointer types are on either side of the '=').


Wade Guthrie
Rockwell International
Anaheim, CA

(Rockwell doesn't necessarily believe / stand by what I'm saying; how could
they when *I* don't even know what I'm talking about???)

guy@auspex.UUCP (Guy Harris) (12/22/88)

 >>  >code must know the type of the lvalue to put the rvalue into the proper
 >>  >representation.  Is this not true?
 >> . . .Why is this any different from
 >> 	int foo; float bar; bar = foo;
 >> which also causes an implicit conversion from "int" to "float"?
 >
 >The statement I made was regarding implicit conversion between pointer
 >types.

Sorry, but with regards to the question of whether the compiler knows
enough about the types involved to do the conversion, that's *not* a
difference.  Pointer types, integral types, structured types, whatever;
the compiler *does* have enough information to perform an implicit
conversion in an assignment, if such a conversion is defined and is
allowed.

>Well, as far as K&R goes, no implicit pointer type conversion
>is made (they do describe how ints can be converted to float (actually
>double, but I digress)).

Whether the language specifies that such conversions are performed or
not is a different issue.  There is sufficient information available to
the compiler that it *can* perform such conversions.  Why is this any
different from:

	int foo;
	struct { int a; int b; } bar;

	foo = bar;

Were a conversion between "int" and a "struct" of the given flavor
defined, the compiler could arrange that it be performed; there doesn't
happen to be such a conversion defined, however.

 >This, I believe, is the root of some of the 
 >discussion lately that the following is non-portable:
 >
 >	#define NULL (char *)0
 >	. . .
 >	int *foo;
 >
 >	foo = NULL;
 >
 >(note that different pointer types are on either side of the '=').

Err, no, it's not the root of the discussion.  The problem isn't just
that this requires a pointer conversion; the problem is that some
compilers may object to converting a "char *" to an "int *" without a
cast (not because they don't know how to do it, but because it's not
*required* to be permitted by the dpANS, and because it could be
difficult or impossible in some implementations).

If it's just a question of different types,

	#define	NULL	(void *)0
	...
	int *foo;

	foo = NULL;

would be no better than your example; however, since the dpANS treats
"void *" differently from other pointers when it comes to conversions,
this construct is OK while the other isn't.

diamond@csl.sony.JUNET (Norman Diamond) (12/23/88)

In article <773@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes:

> ... some
> compilers may object to converting a "char *" to an "int *" without a
> cast (not because they don't know how to do it, but because it's not
> *required* to be permitted by the dpANS, and because it could be
> difficult or impossible in some implementations).
  ^^^^^^^^^    ^^^^^^^^^^

I've got bad news for those compilers.  They may not object to
converting a "void *" to an "int *" and that "void *" must have the
same representation as a "char *".  So if it's difficult, they have
to do difficult things.  If it's impossible, then they don't have C
and they never had malloc().

Sure, any code that ever used malloc() before the invention of (void *)
was already broken, right?  So ANSI isn't really breaking working code.
But to be sensible, compilers really ought to allow conversion between
(char *) and other pointer types.
-- 
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-inventing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?