Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Question about type casting

0 views
Skip to first unread message

Tim Boemker

unread,
Jan 9, 1988, 7:44:21 PM1/9/88
to
What's wrong with this program?

main()
{
int *i;

int j[1];

((int [1]) i) [0] = 1;
}

gw...@brl-smoke.uucp

unread,
Jan 11, 1988, 6:39:51 PM1/11/88
to
In article <508...@hpfcdc.HP.COM> boe...@hpfcdc.HP.COM (Tim Boemker) writes:
-What's wrong with this program?
-main()
-{
- int *i;
- ((int [1]) i) [0] = 1;
-}

How can you turn a pointer into an array? It makes no sense.
Just use i[0] = 1; which is the same as *i = 1;.

Tim Boemker

unread,
Jan 12, 1988, 6:29:56 PM1/12/88
to

Consider int A[1]. A is semantically an array, but the expression "A" is a
pointer to the base of that array. The only differences between a pointer
and array are (1) when the storage is allocated and (2) how index calculations
are made.

Using i[i] instead of *i may be fine if the array in question is one
dimensional, but it doesn't work exactly the same way when the array
is multidimensional. Consider int *A. If I know that A points to
a 10x20 array, I might like to address elements as A[i][j]. I can
do the indexing math myself, as in *(A + i * 20 + j), but that's not
what the question is really about. I want to know why a syntactically
correct and semantically meaningful expression is not allowed.

If you need further provocation, consider this program:

main()
{
int A[1];

( (int [1]) A ) [0] = 0;
}

My C compiler doesn't like that construction, either, presumably for the
same reason that it didn't like the one in the first example. But please
explain to me why it's illegal to cast an expression into it's natural
type! Why can't I cast an array as an array?

Wayne A. Throop

unread,
Jan 12, 1988, 8:22:28 PM1/12/88
to
> boe...@hpfcdc.HP.COM (Tim Boemker)

Lint has this to say about it:

t17.c
==============
(4) illegal lhs of assignment operator
(4) warning: i may be used before set
(3) warning: j unused in function main
(5) warning: main() returns random value to invocation environment

In addition to the minor faults, that no exit value was provided, j was
unused, and i was used before it was initialized, lint claims that the
lhs of the assignment operator is illegal. Which isn't quite right, in
that it really should have complained about the cast.

But even if we accept the dubious legality of the cast, which is
justified only by very broad interpretation of K&R, (how do you convert
a pointer-valued expression to an array-valued expression, anyway?), the
resulting expression being subscripted would have to be a temporary
array (with, for this reason, no aliases), and the whole assignment
becomes a monumentally obfuscated no-op. (In particular, it does *NOT*
by any remote stretch of the imagination initialize i.)

But clearly K&R did not intend to allow anything to be cast to array
type, since casts are defined as conversions, and the allowable
conversions do not include any that result in arrays.

--
I think it's time to stop carping on the blunders of the President and
give him some credit for creativity. I mean, where do you even FIND a
Jewish hard-line conservative Republican pot-smoker?
--- A. Whitney Brown
--
Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw

boe...@hpfcdc.uucp

unread,
Jan 13, 1988, 1:49:57 PM1/13/88
to
> But even if we accept the dubious legality of the cast, which is
> justified only by very broad interpretation of K&R, (how do you convert
> a pointer-valued expression to an array-valued expression, anyway?), the
> resulting expression being subscripted would have to be a temporary
> array (with, for this reason, no aliases), and the whole assignment
> becomes a monumentally obfuscated no-op. (In particular, it does *NOT*
> by any remote stretch of the imagination initialize i.)

> But clearly K&R did not intend to allow anything to be cast to array
> type, since casts are defined as conversions, and the allowable
> conversions do not include any that result in arrays.

1. I'm not so sure about K&R's intentions. True, a cast is a conversion, but
the book does not explicitly define the set of legal conversions; it only
lists conversions. The list is not necessarily complete.

2. Whenever an array identifier appears in an expression, it is treated as
being a pointer to the first element of the array. Casting an expression
as an array is just asking that expression to be used as a pointer to the
base element of a (mutli-dimensional) rectangular collection of elements.
Using an expression of type array is defined, and the object referenced
is not the whole collection of elements but a pointer to the collection
(pp. 195 bottom and 210 top). Saying that the resulting expression would
have to be a temporary array does not make sense under K&R, and it shows
a misunderstanding of its concept of arrays: every array expression of
the form A[i] is equivalent to the pointer expression *(A+i).

Chris Torek

unread,
Jan 13, 1988, 8:59:59 PM1/13/88
to
In article <5...@xyzzy.UUCP> thr...@xyzzy.UUCP (Wayne A. Throop) writes:
[regarding the cast]

>> ((int [1]) i) [0]

>But clearly K&R did not intend to allow anything to be cast to array


>type, since casts are defined as conversions, and the allowable
>conversions do not include any that result in arrays.

Or, to put it another way, the result of a cast is an rvalue, and
C does not have array rvalues.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: ch...@mimsy.umd.edu Path: uunet!mimsy!chris

boe...@hpfcdc.uucp

unread,
Jan 14, 1988, 5:29:21 PM1/14/88
to
> I believe that Standard C does not allow type casting on the left of the
> = sign.

How about this:

int i;
char *c;

c = (char *) &i;

* (int *) c = 0;

Are you saying that Standard C doesn't allow c to be recast in that assignment?

> I have also discovered that SUN and APOLLO C allow this while most other C
> compilers do not???!

So the Sun accepts constructions like ((int [1]) i) [0] = 0; ?
Does it work?

Chris Torek

unread,
Jan 14, 1988, 11:16:24 PM1/14/88
to
In article <508...@hpfcdc.HP.COM> boe...@hpfcdc.HP.COM (Tim Boemker) writes:
>... Consider int *A. If I know that A points to a 10x20 array,

Given that declaration, A cannot point to a 10 x 20 array. It
*can* point to the first element of the first row of such an array
[see example below], from which all other element addresses can be
computed; but it cannot point to the entire array. This is precisely
the difference between a pointer to an object and a pointer to an
array N of objects: only the latter points to the entire array.

>I might like to address elements as A[i][j]. I can
>do the indexing math myself, as in *(A + i * 20 + j), but that's not
>what the question is really about. I want to know why a syntactically
>correct and semantically meaningful expression is not allowed.

Because, given the way C is defined, it is not semantically
meaningful! One small (?) tweak---allow entire arrays to be
rvalues---and it becomes meaningful, but it is not now so.

>Why can't I cast an array as an array?

Because rvalues cannot be arrays, and the result of a cast is an
rvalue. Rvalues *can* be *pointers* to arrays:

int *A, i, j;
...
/* here we decide (by fiat or by analysis) that A points to the
first element of X[10][20], i.e., A == &X[0][0], and then we
set X[i][j] through A: */
((int (*)[20])A)[i][j] = 1;

---although this has the limitation that all but the first dimension
must be known at compile time, and again, this is precisely the
same limitation as the one that exists for formal array parameters.

--------

Note also that the cast replaces the first `array N of' with `pointer
to'. This is the general rule that reduces arrays to pointers in
C expressions (except as arguments to sizeof). If we decide that
A points to the first element of `int Z[10]', and we want to set
Z[5], we can write this:

((int (*))A)[5] = 999;

but this reduces to

((int *)A)[5] = 999;

or just

A[5] = 999;

so this is really rather boring.

Doug Gwyn

unread,
Jan 15, 1988, 8:54:49 AM1/15/88
to
In article <508...@hpfcdc.HP.COM> boe...@hpfcdc.HP.COM (Tim Boemker) writes:
> int A[1];
> ( (int [1]) A ) [0] = 0;
>Why can't I cast an array as an array?

The second `A' above is the NAME of an array. In this context it gets
converted right away into a pointer to its first element. You cannot
legitimately convert a pointer into an array.

Wayne A. Throop

unread,
Jan 17, 1988, 2:22:25 PM1/17/88
to
> boe...@hpfcdc.HP.COM (Tim Boemker)

> I want to know why a syntactically
> correct and semantically meaningful expression is not allowed.
> If you need further provocation, consider this program:
> main()
> {
> int A[1];
> ( (int [1]) A ) [0] = 0;
> }

The question is ill formed. The above cast, while it *is* syntactically
correct, is *NOT* semantically meaningful. The real question is why
were the rules that give C syntax its semantics chosen in such a way as
to make that cast meaningless. For a full answer, one would have to ask
dmr, but the paraphrase of the question Tim asks can be addressed:

> Why can't I cast an array as an array?

To review the rules: casts take the value of the target expression and
convert this value to a new type. An array, when it appears in an
expression, evaluates (yields a value) with pointer type, not array
type. Thus, the cast of what appears to be something to its own type
is, in fact, an attempt to convert a pointer to an array, not an attempt
to cast an array as an array.

Now, why were these rules chosen? Well, the rule that really gets in
the way here is the rule about how arrays are to be treated when
evaluated. This special treatment of arrays in its turn was based on
the unification of array subscripting and address arithmetic in C. In
other words, it is the indirect consequence of an attempt to make C a
simpler and more conceptually unified language. In retrospect, I think
better tradeoffs could have been made, but I don't myself pretend to be
a genius language designer, so I tend to accept C as it is, with only
modest regrets.

--
Giving up on assembly language was the apple in our Garden of Eden:
Languages whose use squanders machine cycles are sinful. The LISP
machine now permits LISP programmers to abandon bra and fig-leaf.
--- Alan J. Perlis
Moon calls them Fortran Machines and Lisp Machines,
but I would prefer to call them fuzzy mammals and
pterodactyls myself.
--- Richard P. Gabriel

Tim Olson

unread,
Jan 17, 1988, 4:22:55 PM1/17/88
to
In article <508...@hpfcdc.HP.COM> boe...@hpfcdc.HP.COM (Tim Boemker) writes:
| > I believe that Standard C does not allow type casting on the left of the
| > = sign.
|
| How about this:
|
| int i;
| char *c;
|
| c = (char *) &i;
|
| * (int *) c = 0;
|
| Are you saying that Standard C doesn't allow c to be recast in that assignment?

I believe that the previous poster really meant that C doesn't allow
*lvalues* to be cast. In your example, 'c' is not an lvalue, but '*c'
is. Therefore, you can write

* (int *) c = 0;

but not

(int)(*c) = 0;


-- Tim Olson
Advanced Micro Devices
(t...@amdcad.amd.com)

Chris Torek

unread,
Jan 17, 1988, 6:06:14 PM1/17/88
to
In some article somewhere, someone writes:
>>I believe that Standard C does not allow type casting on the left of the
>>= sign.

In article <508...@hpfcdc.HP.COM> boe...@hpfcdc.HP.COM (Tim Boemker) writes:
>How about this:
>
>int i; char *c;
>c = (char *) &i;
>* (int *) c = 0;

It is not portable, but it is legal.

The result of a cast is an `rvalue' (R for Right: or in other words,
the kind of thing one finds on the right hand side of an assignment).
Assignments may be made only to `lvalues' (L for Left: the kind of
thing found on the left hand side of an assignment). The C indirection
operator `*' takes an rvalue and yeilds an lvalue, hence the result
of `* (int *) c' is an lvalue.

Doug Gwyn

unread,
Jan 17, 1988, 8:24:30 PM1/17/88
to
In article <508...@hpfcdc.HP.COM> boe...@hpfcdc.HP.COM (Tim Boemker) writes:
>2. Whenever an array identifier appears in an expression, it is treated as
> being a pointer to the first element of the array.

I can think of two exceptions to this: when the array name is the operand of
sizeof or the operand of &.

> Casting an expression
> as an array is just asking that expression to be used as a pointer to the
> base element of a (mutli-dimensional) rectangular collection of elements.

How do you figure that? A cast operator is supposed to accomplish a virtual
assignment of the operand into an object of the specified type, an array in
this case, and we should all know that C does not support assignment into an
array.

> Saying that the resulting expression would

> have to be a temporary array does not make sense under K&R, ...

Excuse me, but saying anything else does not make sense.

The Beach Bum

unread,
Jan 18, 1988, 1:25:04 AM1/18/88
to
In article <10...@mimsy.UUCP>, ch...@mimsy.UUCP (Chris Torek) writes:
> In some article somewhere, someone writes:
> >>I believe that Standard C does not allow type casting on the left of the
> >>= sign.
>
> In article <508...@hpfcdc.HP.COM> boe...@hpfcdc.HP.COM (Tim Boemker) writes:
> >How about this:
> >
> >int i; char *c;
> >c = (char *) &i;
> >* (int *) c = 0;
>
> It is not portable, but it is legal.

I believe it used to be portable. Now that X3J11 has mangled the language,
it isn't guaranteed to be portable. If I recall correctly, a pointer to
any object can _portably_ be converted to a pointer to a smaller object and
back again. Thus,

int i; char * cp;
cp = (char *) &i;
* (int *) cp = 0;

is portable, but

int *ip; char c;
ip = (int *) &c;
* (char *) ip = '0';

is not.

> The result of a cast is an `rvalue' (R for Right: or in other words,
> the kind of thing one finds on the right hand side of an assignment).
> Assignments may be made only to `lvalues' (L for Left: the kind of
> thing found on the left hand side of an assignment). The C indirection
> operator `*' takes an rvalue and yeilds an lvalue, hence the result
> of `* (int *) c' is an lvalue.
> --
> In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)

Chris, that's some good voodoo. A cast takes an object of whatever
type it happens to be, and whatever state of (l|r)value-ness and changes
it's type, but not it's (l|r)value-ness. The difference between lvalue
expressions and rvalue expressions is more obvious in a language such
as BLISS with all those silly dots. . . . . .

The only restriction on what can be on the left hand side of an `=' is
having an address and a type, or being finaglable into having both. I
can cast an obvious rvalue like `2' into an int * with ((int *) 2).
This thing can now appear on either side -

*((short *) 2) = *((short *) 4);

- John.
--
John F. Haugh II SNAIL: HECI Exploration Co. Inc.
UUCP: ...!ihnp4!killer!jfh 11910 Greenville Ave, Suite 600
"Don't Have an Oil Well? ... Dallas, TX. 75243
... Then Buy One!" (214) 231-0993 Ext 260

Wayne A. Throop

unread,
Jan 18, 1988, 10:31:06 AM1/18/88
to
> boe...@hpfcdc.HP.COM (Tim Boemker)
>> [... (if it were legal) the expression cast to array type ...]

>> being subscripted would have to be a temporary
>> array (with, for this reason, no aliases), and the whole assignment
>> becomes a monumentally obfuscated no-op.
> Using an expression of type array is defined, and the object referenced
> is not the whole collection of elements but a pointer to the collection
> (pp. 195 bottom and 210 top).

This assertion is somewhat misleading. In particular, the passages
appealed to above do not say that an expression of type array *refers*
to a pointer, but that it is (usually) *converted* to a pointer. The
exception to this rule, when target of sizeof, makes this distinction
clear. A "conversion" is not a "reference". And "conversion" is not
commutative, so the conversion from array to pointer in no way implies
that a conversion from pointer to array is legal.

> Saying that the resulting expression would
> have to be a temporary array does not make sense under K&R, and it shows
> a misunderstanding of its concept of arrays: every array expression of
> the form A[i] is equivalent to the pointer expression *(A+i).

It shows no such thing. Remember the context here: I said that was what
would happen *IF* the cast made sense in K&R, which it does not.
Pointing out that a temporary array doesn't make sense in K&R is exactly
the illegality I was suspending for the purposes of discussing what that
expression might mean.

I said that the resulting expression would have to be a temporary array
because that is what casting is all about. Or, more precisely, casts
always result in rvalues, and an rvalued array is an oxymoron under K&R.
Both the tutorial and reference sections on casts are very explicit
about this in K&R. The tutorial says that casts work as if by
assignment to a temporary of the cast type. This is clearly impossible
for arrays. The syntax in the reference makes it clear that casts
result in rvalues. Again, this is impossible for arrays.

However, I can see now (I think) what Tim is getting at. Which is, why
isn't the cast ((type [N])E) equivalent to the cast ((type *)E)? And
the answer is that this special case was not allowed for in K&R. The
equivalent special case, making these two types equivalent when they
appear as formal arguments, *was* made, but it is, indeed, a special
case, and the analogous special case for casts was *not* made. Whether
it should have been made or not is moot: the point is that it *was*
*not* made. (And in my humble opinion, the special case for array
formal arguments should not have been made either.)

--
Giving up on assembly language was the apple in our Garden of Eden:
Languages whose use squanders machine cycles are sinful. The LISP
machine now permits LISP programmers to abandon bra and fig-leaf.
--- Alan J. Perlis
Moon calls them Fortran Machines and Lisp Machines,
but I would prefer to call them fuzzy mammals and
pterodactyls myself.
--- Richard P. Gabriel

Chris Torek

unread,
Jan 18, 1988, 1:43:44 PM1/18/88
to
>In article <10...@mimsy.UUCP> I claimed taht

>>>int i; char *c;
>>>c = (char *) &i;
>>>* (int *) c = 0;
>is not portable, but it is legal.

In article <29...@killer.UUCP> j...@killer.UUCP (The Beach Bum) writes:
>I believe it used to be portable.

It used to be `portable by default': that is, there was no portable
way to do it at all, but that came closest.

>Now that X3J11 has mangled the language, it isn't guaranteed to be
>portable.

Doug Gwyn mentioned that the current draft makes it portable again.
(My interpretation of his remark; beware.)

>>The result of a cast is an `rvalue' ....
>>Assignments may be made only to `lvalues' .... The C indirection
>>operator `*' takes an rvalue and yeilds an lvalue ....

>Chris, that's some good voodoo.

?

>A cast takes an object of whatever type it happens to be, and whatever
>state of (l|r)value-ness and changes it's type,

Good so far. Note that any lvalue can be converted to an rvalue.
Note also that the cast may change its bit-pattern and/or shape (e.g.,
casting short to double).

>but not it's (l|r)value-ness.

Whoa! Stop! No! The result of a cast is effectively that of
assigning to an unnamed temporary variable with the type given
in the cast. This is an rvalue.

>The difference between lvalue expressions and rvalue expressions is
>more obvious in a language such as BLISS with all those silly dots. . . .

No: If I understand correctly, in BLISS, every expression can be
veiwed as both an lvalue *and* an rvalue. This is untrue in C.

>The only restriction on what can be on the left hand side of an `=' is
>having an address and a type, or being finaglable into having both.

No: it must be an lvalue. Naturally, all lvalues have a type; most
even have addresses, although some (register) might not. But this
is not the abstraction defined by the C language. [**]

>I can cast an obvious rvalue like `2' into an int * with ((int *) 2).

Yet it is still an rvalue.

>This thing can now appear on either side -
>
> *((short *) 2) = *((short *) 4);

(There are no `int *'s above.) Once again, `*' (indirection) takes
an rvalue and produces an lvalue. *(short *)2, if it means anything,
means an lvalue at 2 (whatever that is). If `2' happens to be a
valid address for a variable of type `short', this goes; if not,
you get a segmentation fault or other weird error.

If I had my K&R here, I would check, but I believe the only operators
that convert rvalues to lvalues are unary `*' (indirect, not
multiply) and `->' (pointer-to-structure-member). All others result
in rvalues; some, such as unary `&' (address of) work only on
lvalues.

Mathematically speaking, unary `&' and `*' are inverse functions.
Unary `&' takes an lvalue of type `T' and produces an rvalue of
type `pointer to T'; unary `*' takes an rvalue of type `pointer to
T' and produces an lvalue of type `T'. The <value, type> pairs
from unary `&' must be distinct for distinct lvalues [*], and there
may be only one value produced for any particular lvalue. This
makes it an invertible function; `*' is then defined as the inverse
function. While `*' is a well-behaved function on conventional
architectures, all that the language requires is that it be the
inverse of `&'.

-----
[*] Actually, <v,t> pairs need not be distinct for `dead' lvalues,
e.g., `int *i1,*i2; { int j1; i1 = &j1; } { int j2; i2 = &j2; }'.
The language states that using the <v,t> pair of a dead lvalue is
an error. Whether certain different-looking lvalues are in fact
the same on segmented architectures with built-in aliasing (80x86)
is open to debate, but there is no legal way to obtain two different
<segment,offset> pairs that yeild the same address. That is, it
is easy to do, but it is not part of the C language itself.

[**] The strongest statements the C language makes about addresses
are: they exist; they have values of type `pointer to T'; some form
of arithmetic, with the two operations A + I => A and A - A -> I,
works on them; the legal range for the integer value I is defined
by the declaration (array) or allocation (via malloc) of the object;
adding a legal integer I to an address A yeilds an address A1 such
that A1 - A = I; successively adding 1 to an address yeilds successive
array elements. (I think that covers it: the rest can be derived.)


--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)

Domain: ch...@mimsy.umd.edu Path: uunet!mimsy!chris

Doug Gwyn

unread,
Jan 19, 1988, 9:57:42 AM1/19/88
to
In article <29...@killer.UUCP> j...@killer.UUCP (The Beach Bum) writes:
>In article <10...@mimsy.UUCP>, ch...@mimsy.UUCP (Chris Torek) writes:
>> The result of a cast is an `rvalue' (R for Right: or in other words,
>> the kind of thing one finds on the right hand side of an assignment).
>> Assignments may be made only to `lvalues' (L for Left: the kind of
>> thing found on the left hand side of an assignment). The C indirection
>> operator `*' takes an rvalue and yeilds an lvalue, hence the result
>> of `* (int *) c' is an lvalue.
>Chris, that's some good voodoo. A cast takes an object of whatever
>type it happens to be, and whatever state of (l|r)value-ness and changes
>it's type, but not it's (l|r)value-ness.

If you don't know what you're talking about, you should shut up!

Chris is right (as usual) -- a cast produces a non-lvalue (which you
may call an `rvalue' if you wish), and it is only the result of
applying a * operator that is an lvalue as required for the target
of the assignment.

A cast performs a simultaneous conversion and virtual assignment of
its operand into an unnamed temporary register, in effect. There
is no way that the result can be conceived of as being addressable.

>The only restriction on what can be on the left hand side of an `=' is
>having an address and a type, or being finaglable into having both.

Wrong -- it must be a modifiable lvalue.

John Haugh

unread,
Jan 19, 1988, 1:14:20 PM1/19/88
to
In article <10...@mimsy.UUCP>, ch...@mimsy.UUCP (Chris Torek) writes:
> >In article <10...@mimsy.UUCP> I claimed taht
> >>>int i; char *c;
> >>>c = (char *) &i;
> >>>* (int *) c = 0;
> >is not portable, but it is legal.
>
> In article <29...@killer.UUCP> j...@killer.UUCP (The Beach Bum) writes:
> >I believe it used to be portable.
>
> It used to be `portable by default': that is, there was no portable
> way to do it at all, but that came closest.

Sorry Chris, here's the reference I was refering to in my `I believe'
statement:

C Language Reference Manual, D. M. Ritchie, 1978

Section 14.4, paragraph 4

"A pointer to one type may be converted to a pointer another
type. The resulting pointer may cause addressing exceptions
if the subject pointer does not refer to an object suitably
aligned in storage. It is guaranteed that a pointer to an
object of a given size may be converted to a pointer to an
object of a smaller size and back again without change."

[ reprinted without permission ]

Sounds like the closest statement to being portable I can come up
with.

> >Now that X3J11 has mangled the language, it isn't guaranteed to be
> >portable.
>
> Doug Gwyn mentioned that the current draft makes it portable again.
> (My interpretation of his remark; beware.)

Except that the X3J11 (how close is that to XJ6 or XJS ;-) committee
changed it from `any smaller object' to `may be cast to and from a
void object' (ie, replace (char *) with (void *) ). This is what I've
read. I believe the ability to cast to/from a short has been removed.

> >>The result of a cast is an `rvalue' ....
> >>Assignments may be made only to `lvalues' .... The C indirection
> >>operator `*' takes an rvalue and yeilds an lvalue ....
>
> >Chris, that's some good voodoo.
>
> ?
>
> >A cast takes an object of whatever type it happens to be, and whatever
> >state of (l|r)value-ness and changes it's type,
>
> Good so far. Note that any lvalue can be converted to an rvalue.
> Note also that the cast may change its bit-pattern and/or shape (e.g.,
> casting short to double).
>
> >but not it's (l|r)value-ness.
>
> Whoa! Stop! No! The result of a cast is effectively that of
> assigning to an unnamed temporary variable with the type given
> in the cast. This is an rvalue.

Yes, you are right. I deleted the rest of the mess I made. I misunderstood
you to be saying that `*' somehow turned things into l-values only, which
contradicts being able to dereference a pointer and get an r-value. The
example was intended to show U-star in both positions.

The best point you [ went on to make ] is that '&' and '*' are complimentary
operations.

> --
> In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
> Domain: ch...@mimsy.umd.edu Path: uunet!mimsy!chris

In-Real-Life: Captain Fanastic, Defender of Bathroom Soap Scum,

But in this life, I remain -

Chris Torek

unread,
Jan 20, 1988, 10:22:31 AM1/20/88
to
In article <29...@killer.UUCP> j...@killer.UUCP (John Haugh) writes:
>here's the reference ...

>
> C Language Reference Manual, D. M. Ritchie, 1978

(all kneel :-) )

> Section 14.4, paragraph 4
>
> "A pointer to one type may be converted to a pointer another
> type. The resulting pointer may cause addressing exceptions
> if the subject pointer does not refer to an object suitably
> aligned in storage. It is guaranteed that a pointer to an
> object of a given size may be converted to a pointer to an
> object of a smaller size and back again without change."

------- ----

>Sounds like the closest statement to being portable I can come up
>with.

Presumably `smaller size' means `sizeof(*p)' for that pointer results
in a smaller integer. The one glitch with this definition is that
there is nothing that says that an object whose size is the *same*
as sizeof(char) has pointers that can be converted back and forth:

short *sp; /* some compiler with 8-bit shorts */
char *cp;
...
printf("%d %d\n", sizeof(*sp), sizeof(*cp)); /* prints `1 1' */
cp = (char *)sp;
if (sp == (short *)cp) {
/* always get here? maybe! */
}

I *will* say that it would have to be one cretinous compiler that
made sp != (short *)cp.

This sort of loose end (or loophole, if you will) is a large part
of what makes K&R not `a C standard'. Language standards are an
awful lot like laws. . . .

0 new messages