limitations of casts, pointer and function declarartions...

Guido van Rossum guido at mcvax.UUCP
Tue Oct 30 23:19:02 AEST 1984


In article <120 at harvard.ARPA> breuel at harvard.ARPA (Thomas M. Breuel) writes:
>	int x;
>	char *y;
>/*### [cc] illegal lhs of assignment operator = %%%*/
>	(char *)x = y;

Sorry, you're thinking Algol-68.  What you need is:
	*( (char*) &x ) = y;

Let me try to explain why.  The difference between lvalues and rvalues
in C is quite different from the difference between 'int' and 'ref' 'int'
in Algol-68.  Here are the rules:

The following are declared to be lvalues:
- names of variables (except arrays, see elsewhere in net.lang.c :-);
- the expression *something, where 'something' may be any expression;
- e1[e2]; this can be deduced from the previous rule because, by definition,
  e1[e2] means *((e1)+(e2)) /* remember special semantics of pointer+int */;
- an lvalue between parentheses is still an lvalue.
Everything else is an rvalue.  (Summary: lvalues have addresses;
rvalues don't.  But lvalues *are* not addresses.  They're variables.)

In expressions (note that assignments are also expressions), there is a need
for lvalues and rvalues.  An lvalue is needed:
- at the left-hand side of an assignment operator (hence the name);
- as an argument to the auto-increment/decrement operators ++ and --
  (note that the RESULT of these is only an rvalue!);
- as an argument to the address-of operator, &something.
Everywhere else, an rvalue is needed.
When an lvalue is found where an rvalue is needed, it is turned into
an rvalue by using the value contained in its address.

Again, summarizing: after int x;, x and 1 have exactly the same type;
only x is an lvalue and 1 is an rvalue.


>(the solution here is, of
>course, to write 'x = (int)y;', but can the compiler make this
>transformation without ambiguity in general?).

Huh?  This assigns to all (sizeof int) bytes of x, while
	* ( (char*) &x ) = y;
assigns only to x's first (or last) byte.  What did you want?


>typedef ref *ref;

Looks very much like Algol-68 again (except that there, you can never
use the thing at all, because there are no unrestricted casts as in C...).
The fact is, and this will not change, that a typedef cannot contain
references to itself (the typedef-ed name becomes defined only *after*
the typedef has been processed by the compiler).  The only way to build
recursive types is using structure pointers, as it *is* allowed to write
	struct foo *x; /* but not struct foo x; !!! */
when struct foo is not yet declared (see response by Doug Gwyn).

>typedef long base;	/* change this to int type with size of pointer */
>typedef base *ref;
>#define deref(thing) ((ref)(*thing))

How about this:

	#define deref(thing) (* (ref*)(thing))

Because the '*' operator is at the outermost level, this macro
expands to an lvalue, with the same type as your macro, and can thus
be used in an assignment.


>typedef fun (*fun)();

Same remarks: typedefs can't be recursive.  Sorry, that's the way it is.

--
	Guido van Rossum, "Stamp Out BASIC" Committee, CWI, Amsterdam
	guido at mcvax.UUCP

"Don't stop.  Go right on complaining.  It's *so* beautiful!"



More information about the Comp.lang.c mailing list