[comp.lang.c] "array" vs. "&array" ?

martin@mwtech.UUCP (Martin Weitzel) (12/23/89)

Some days ago I posted a question if it is legal (or makes sense)
to write a "&" before an array. I received a few responses, some
mentioned, that an "&" before an array is illegal and/or that the
compiler simply ignores it.

I will not object to this - my compiler with ISCs 386/ix also ignores
it - but I will present you a fragment of C-Code, which can not be
compiled (without warnings) with this type of compilers.

To my understanding, the following *is* a type mismatch:
-----------------------------------------------------------------------
main()
{
	char a[10], (*p)[10];

	p = a;
warning: illegal pointer combination, op =
}
-----------------------------------------------------------------------
The compiler seems to take my point of view.

Then I'll try to get it right (to my understanding):
-----------------------------------------------------------------------
main()
{
	char a[10], (*p)[10];

	p = &a;
warning: & before array or function: ignored
warning: illegal pointer combination, op =
}
-----------------------------------------------------------------------
Now, what's that? I've made it right, then the compiler throws out
my "&" and complains that it is wrong. Of course it is wrong now,
the compiler just *made* it wrong!

And to all of you who want to now, why I might want to do such strange
things, look at the following:
-----------------------------------------------------------------------
main()
{
	char m[20][10], (*p)[10];

	p =  m[0];
	/*  ^ to "&" or not to "&", that is the question */
	
	/* do something with (*p)[x] -- a single char
	   and have the possibility to increment p to
           point to the next group of 10 char-s */
}
-----------------------------------------------------------------------
or another one:
-----------------------------------------------------------------------
char (*foo())[10]
{
	static char m[20][10] = {
		/* some initialization */
	};
	int i;
	/* do some calculations giving a value to i */
	return  m[i];
	/*     ^ to "&" or not to "&", that is the question */
}
-----------------------------------------------------------------------
I simply can't get it right! What am I missing?

Or is the compiler, that ignores the &, something missing?

(OK, before you post it: I *know* that I can supress the warning
with a typecast, but I think typecasts should only be used as
last resort and not be necessary if you want nothing more than
a perfectly legal and reasonable assignment or function return!)
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

cpcahil@virtech.uucp (Conor P. Cahill) (12/23/89)

In article <571@mwtech.UUCP>, martin@mwtech.UUCP (Martin Weitzel) writes:
> To my understanding, the following *is* a type mismatch:
> -----------------------------------------------------------------------
> main()
> {
> 	char a[10], (*p)[10];
> 
> 	p = a;
> warning: illegal pointer combination, op =
> }

Did you try a cast?  Try the following:

main()
{
 	char a[10], (*p)[10];
 
 	p = (char (*)[10]) a;
}

this worked fine for me.  No complaints from the compiler.

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

chris@mimsy.umd.edu (Chris Torek) (12/24/89)

In article <571@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes:
>Some days ago I posted a question if it is legal (or makes sense)
>to write a "&" before an array. I received a few responses, some
>mentioned, that an "&" before an array is illegal and/or that the
>compiler simply ignores it.

This is the K&R-1 (`Classic C') interpretation.  In K&R-2/ANSI (`New C'),
& before an array name produces a value with a different type.

Given

	basetype arr[SIZE];	/* declares arr as `array SIZE of basetype' */

the type of `arr' is `array SIZE of basetype'.  In a value context,
such as the right hand side (but not the left side) of an assignment
operator, an object of type `array N of T' degenerates to a value of
type `pointer to T' whose value is the address of the 0'th element
of the object.  This is the same in both Classic C and New C.  As
the argument of the address-of operator `&', however, there is a
difference.  In Classic C, if the argument is an object of type
`array N of T', the `&' is ignored (with a warning), while in New C,
the result is instead a pointer to that object: a value with type
`pointer to array N of T' whose value is the address of the object.
Thus:

	arr

produces a value of type `pointer to basetype', value = &arr[0],
but

	&arr

produces either a warning (Classic C), or a value of type `pointer
to array SIZE of basetype' (New C).

>To my understanding, the following *is* a type mismatch:
>-----------------------------------------------------------------------
>main()
>{
>	char a[10], (*p)[10];
>
>	p = a;
>warning: illegal pointer combination, op =
>}

Yes, it is.  To make it correct (but require New C):

>	p = &a;

Unfortunately, when handed to an Old C compiler, you get:

>warning: & before array or function: ignored
>warning: illegal pointer combination, op =

>And to all of you who want to now, why I might want to do such strange
>things, look at the following:
>-----------------------------------------------------------------------
>main()
>{
>	char m[20][10], (*p)[10];
>
>	p =  m[0];
>	/*  ^ to "&" or not to "&", that is the question */

In both Classic and New C, this can be expressed as

	p = m + 0;

because `m' has type `array 20 of array 10 of char', and hence `m'
in a value context (such as an operand of `+') produces a value of
type `pointer to array 10 of char' whose value is the address of m[0].
In New C, of course, it can also be written

	p = &m[0];

since & accepts an object of type `array 10 of char' and produces a
value of type `pointer to array 10 of char' whose value is the address
of that object (m[0]).  It is just those darned Classic C compilers
that refuse to recognise this.

>	/* do something with (*p)[x] -- a single char
>	   and have the possibility to increment p to
>           point to the next group of 10 char-s */
>}
>-----------------------------------------------------------------------
>or another one:
>-----------------------------------------------------------------------
>char (*foo())[10]
>{
>	static char m[20][10] = {
>		/* some initialization */
>	};
>	int i;
>	/* do some calculations giving a value to i */
>	return  m[i];
>	/*     ^ to "&" or not to "&", that is the question */
>}

Again, `return m + i' is the only solution that works everywhere.

Incidentally, if you have PCC source, you can add `&arr' to your Classic
C compiler (the result is definitely an improvement) merely by *removing*
several lines of code.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

chris@mimsy.umd.edu (Chris Torek) (12/24/89)

In article <1989Dec23.151411.3688@virtech.uucp> cpcahil@virtech.uucp
(Conor P. Cahill) writes:
[re obtaining the address of an array, rather than the address of an
element of that array]
>main()
>{
> 	char a[10], (*p)[10];
> 
> 	p = (char (*)[10]) a;
>}

This is exceedingly ugly, although it is probably portable.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

dskim@eng.umd.edu (Daeshik Kim) (12/28/89)

In article <21419@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>
>	&arr
>
>produces either a warning (Classic C), or a value of type `pointer
>to array SIZE of basetype' (New C).
>
>
>>	p = &a;
>
>Unfortunately, when handed to an Old C compiler, you get:
>
>>warning: & before array or function: ignored
>>warning: illegal pointer combination, op =
>

	If I define "char a[10];" and use " &a" (e.g. address of array a)
	, isn't this undefined?

	To my understanding, "&a" is the address of the address of the base
	of 10 bytes mem.  The only place I can think of, is where the compiler
	keeps the info. of allocated memory( activation record ).

	I'm not expert; please give me some enlightenment.
--
	Daeshik Kim	H: (301) 445-0475/2147 O: (703) 689-7308 (M,W,F)
	SCHOOL:	dkim@cscwam.umd.edu (uunet!haven!cscwam.umd.edu!dkim)
		dskim@eng.umd.edu (uunet!haven!eng.umd.edu!dskim)
	WORK:	dkim@daffy.uu.net (uunet!daffy!dkim)

chris@mimsy.umd.edu (Chris Torek) (12/29/89)

>In article <21419@mimsy.umd.edu> I wrote:
>>	&arr
>>produces either a warning (Classic C), or a value of type `pointer
>>to array SIZE of basetype' (New C).
>>>	p = &a;
>>Unfortunately, when handed to an Old C compiler, you get:
>>>warning: & before array or function: ignored
>>>warning: illegal pointer combination, op =

In article <1989Dec28.100415.17825@eng.umd.edu> dskim@eng.umd.edu
(Daeshik Kim) writes:
>	If I define "char a[10];" and use " &a" (e.g. address of array a)
>	, isn't this undefined?

No.  Reread <21419@mimsy.umd.edu>, this time without preconceived notions:

>	To my understanding, "&a" is the address of the address of the base
>	of 10 bytes mem.  The only place I can think of, is where the compiler
>	keeps the info. of allocated memory( activation record ).

No.  `a' (as defined above) is the name of an array, therefore

	&a

is

	<address-of> <object, array 10 of char, a>

Some C books (including K&R-1) would lead you to believe that anywhere
`a' occurs in C code it means `the address of the first of ten characters'.
This is false: `a' means `the variable a'.  In *value contexts* (NOT
everywhere), it is *converted to* (does not start out as) a value
that has a pointer type (namely `char *').  The operand of unary `&',
however, is NOT in a value context.  (If it were, you could ask for
`&(a + b)'.)  It is in an object context, and objects in object contexts
stay objects: arrays do not degenerate into pointers.  The `&' thus
sees the object (array 10 of char) and not the address (pointer to
a[0]) that, e.g., `char *p = a;' sees.

Again, in Old (or Classic or K&R-1) C, the unary `&' does not accept
arrays or functions, but in New (or ANSI or K&R-2) C, it does accept
arrays.  The obvious thing for `address of <object,array...>' to become
is `<value,pointer to array...>', and this is what happens (in NEW C ONLY).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

randolph@ektools.UUCP (Gary L. Randolph) (01/03/90)

In article <1989Dec28.100415.17825@eng.umd.edu> dskim@eng.umd.edu (Daeshik Kim) writes:
>In article <21419@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>>
>>	&arr
>>
>>produces either a warning (Classic C), or a value of type `pointer
>>to array SIZE of basetype' (New C).
>>
>>
>>>	p = &a;
>>
>>Unfortunately, when handed to an Old C compiler, you get:
>>
>>>warning: & before array or function: ignored
>>>warning: illegal pointer combination, op =
>>
>
>	If I define "char a[10];" and use " &a" (e.g. address of array a)
>	, isn't this undefined?

***>    That depends upon which generation of C compiler you are using!!!
***>    Unfortunately, there are *THREE* reactions a C compiler may have
***>    to taking the address of an array name.

***>     1.) Compilers strictly conformant to K&R C will generate an error
***>         to indicate that &array_name is undefined.
***>     2.) Since the novice C programmer made this mistake so frequently,
***>         compiler vendors 'got nice' and simply generated a warning and
***>         informed you that the '&' was ignored. (How kind!?)
***>     3.) ANSI extended the language definition to allow taking the 
***>         address of an array name, so an ANSI conformant compiler will
***>         now (correctly) yield pointer to array of T, or pointer to
***>         pointer to T.

***>    IMHO, this extension is reasonable, though I have not found a place
***>    for it in the applications on which I have worked.


           Gary

chris@mimsy.umd.edu (Chris Torek) (01/04/90)

In article <2368@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
>3.) ANSI extended the language definition to allow taking the 
>    address of an array name, so an ANSI conformant compiler will
>    now (correctly) yield pointer to array of T, or pointer to
>    pointer to T.

There is no `or' about it!  The result is a pointer to an array, NOT
a pointer-to-pointer.  The two types are completely different.

POINTERS AND ARRAYS ARE NOT NOW AND NEVER HAVE BEEN EQUIVALENT IN C.

There are a few special cases under which an object of type `array
N of T' is converted to a value of type `pointer to T', and under which
a declaration of type `array N of T' is converted to a declaration of
type `pointer to T'.  This does not make the types equivalent.  They
are not interchangeable.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

randolph@ektools.UUCP (Gary L. Randolph) (01/09/90)

In article <21621@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>In article <2368@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
>>3.) ANSI extended the language definition to allow taking the 
>>    address of an array name, so an ANSI conformant compiler will
>>    now (correctly) yield pointer to array of T, or pointer to
>>    pointer to T.
>
>There is no `or' about it!  The result is a pointer to an array, NOT
>a pointer-to-pointer.  The two types are completely different.
>
>POINTERS AND ARRAYS ARE NOT NOW AND NEVER HAVE BEEN EQUIVALENT IN C.

True, but array *names* may certainly be treated as constant pointers.
Chris, I agree with what you say.  I have to admit, however, that the
sentence in question is taken verbatim from Harbison and Steele, pg 273,
section 11.6.4.

>
>There are a few special cases under which an object of type `array
>N of T' is converted to a value of type `pointer to T', and under which
>a declaration of type `array N of T' is converted to a declaration of
>type `pointer to T'.  This does not make the types equivalent.  They
>are not interchangeable.

Well, again I agree but then I am confused when I read, in K&R2, page 
200 A7.1: 

If the type of an expression or subexpression is "array of T," for
some type T, then the value of the expression is a pointer to the
first object in the array, and the type of the expression is altered
to "pointer to T".

They do not say that the above is true only for a few special cases.

Based on experience, I agree with Chris, but then I am confused when
reading the above in two texts that I rarely question.

Is the quote from Harbison and Steele wrong?

Am I wrong in the inference from K&R that:

float arrf[3] = {1.2,2.3,3.4};
arrf;            /*evaluates to pointer to float according to K&R*/
&arrf;           /*evaluates to pointer to pointer to float (my inference)*/

Now I'm aware that if we look at a two dimensional array that if
int arr[2][3];	/*for example*/
then it is quite different to say

&arr evaluates to pointer to array of int
as opposed to
&arr evaluates to pointer to pointer to int

since, in the first case, arr++ would increment sizeof(arr) and in the
second case, arr++ would increment sizeof(pointer), which is not right.

So how does page 200 of K&R apply here? Chris?

Gary

chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) (01/10/90)

In article <2378@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
>   Am I wrong in the inference from K&R that:

>   float arrf[3] = {1.2,2.3,3.4};
>   arrf;            /*evaluates to pointer to float according to K&R*/

When declaring/defining arrf, space is allocated for a pointer to the array
_in the symbol table_, _not_ in the actual object code.  (i.e.  this address
may not manifest itself in the object code at all if never referenced)

> &arrf; /*evaluates to pointer to pointer to float (my inference)*/

So now, as I understand it, you're asking for a pointer to something that
exists in the symbol table that is often stripped from the final version of
programs.

This doesn't make sense to me, nor does it make sense to several of the
compilers I've used.  Some have printed a message to the effect, "Surely you
must be joking.  I'll ignore the '&' and pretend you just wrote 'arrf', you
naughty, naughty little programmer."

My question: Is this now part of ANSI C?  (Yuk!)


--
	   Chuck Phillips -- chuckp%bach.ncr-fc.FtCollins.NCR.COM

bagpiper@pnet02.gryphon.com (Michael Hunter) (01/10/90)

chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) writes:
>In article <2378@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
>>   Am I wrong in the inference from K&R that:
>
>>   float arrf[3] = {1.2,2.3,3.4};
>>   arrf;            /*evaluates to pointer to float according to K&R*/
>
>When declaring/defining arrf, space is allocated for a pointer to the array
>_in the symbol table_, _not_ in the actual object code.  (i.e.  this address
>may not manifest itself in the object code at all if never referenced)
>
>> &arrf; /*evaluates to pointer to pointer to float (my inference)*/
>
>So now, as I understand it, you're asking for a pointer to something that
>exists in the symbol table that is often stripped from the final version of
>programs.
>
This must be done by the linker or some postprocessor of the
executable...otherwise how could the compiler tell that a object is not
referenced in some other module (even static functions or varaibles via
pointers.)

                                Michael

Mike Hunter - Box's and CPU's from HELL: iapx80[012]86, PR1ME 50 Series, 1750a
UUCP: {ames!elroy, <routing site>}!gryphon!pnet02!bagpiper
INET: bagpiper@pnet02.gryphon.com

chris@mimsy.umd.edu (Chris Torek) (01/10/90)

In article <21621@mimsy.umd.edu> I wrote more stuff about pointers
and arrays being quite different, except in a few special cases.

In article <2378@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
>... the sentence in question is taken verbatim from Harbison and Steele,
>pg 273, section 11.6.4.

Since I do not have H&S (I should, if only for this sort of thing), I
canot guess why they might have put in an `... or pointer to pointer to'.

[me]
>>There are a few special cases under which an object of type `array
>>N of T' is converted to a value of type `pointer to T', and under which
>>a declaration of type `array N of T' is converted to a declaration of
>>type `pointer to T'.  This does not make the types equivalent.  They
>>are not interchangeable.

>Well, again I agree but then I am confused when I read, in K&R2, page 
>200 A7.1: 
>
>If the type of an expression or subexpression is "array of T," for
>some type T, then the value of the expression is a pointer to the
>first object in the array, and the type of the expression is altered
>to "pointer to T".

This must be mentally applied to `places where lvalues (object
designators) appear where values are desired'.  For instance, given

	T arr[N];

when

	p = arr;

appears, a value is desired, and the quoted sentence applies.

>They do not say that the above is true only for a few special cases.

It is an extremely common special case (values, i.e., expressions,
appear everywhere).  Nonetheless, it is a special case.

>Based on experience, I agree with Chris, but then I am confused when
>reading the above in two texts that I rarely question.

>Is the quote from Harbison and Steele wrong?

Not knowing the context, I canot say.

>Am I wrong in the inference from K&R that:
>
>float arrf[3] = {1.2,2.3,3.4};
>arrf;            /*evaluates to pointer to float according to K&R*/
>&arrf;           /*evaluates to pointer to pointer to float (my inference)*/

Yes, this is wrong.  `arrf', by itself, is in a value context: it
is a statement which evaluates to the value of `arrf'.  Thus, it
undergoes the change from

	[value context] <object, array 3 of float, arrf> ;

to

	[value context] <value, pointer to array 3 of float, &arrf[0]> ;

`&arrf', however, consists of two parts.  First there is a unary `&',
and its argument is examined in *object* context.  Here objects that
are arrays are *not* converted.  We have

	[value context] & [object context] <object, array 3 of float, arrf> ;

and the `&' is applied to an object of type array 3 of float, yeilding
a value (`&' produces values, not objects) of type `pointer to array 3
of float'.  Since this is a value, nothing further happens.

For comparison, when evaluating

	a = b;		/* assume a and b are `int' */

I would write:

	[value context] ( [object context] a = [value context] b ) ;

To evaluate the right hand side:

	[value context] <object, int, b>

and convert by the rule `an object that is not an array, when in value
context, becomes a value by replacing the object with its current value'.
(Classic C has some type extension rules here that New C defers until
actually required.)  So, if `b' has the value `42', we replace it with

	<value, int, 42>

and now we have

	[value context]
	  ( [object context] <object, int, a> = <value, int, 42> );

Since we have an object on the left hand side, and an object context,
we can do the assignment, setting `a' to 42.  Now we have

	[value context] ( [result of assignment to a] )

The result of an assignment is the value you would get if you examined
the assigned-to object: in this case the int-value 42, so it is a value
in a value context and all is well.

>Now I'm aware that if we look at a two dimensional array that if
>int arr[2][3];	/*for example*/
>then it is quite different to say
>
>&arr evaluates to pointer to array of int
>as opposed to
>&arr evaluates to pointer to pointer to int

(these are both wrong)

>since, in the first case, arr++ would increment sizeof(arr) and in the
>second case, arr++ would increment sizeof(pointer), which is not right.
>
>So how does page 200 of K&R apply here? Chris?

In Classic C, `&arr' is, as always, an error.  In New C, `&arr' produces
a value of type `pointer to array 2 of array 3 of int'.  Write it down
(this time I will leave out the [context] notations):

	a. for `int (*p)[2][3]; p = &arr':

	p = & <object, array 2 of array 3 of int, arr>

& takes object context, produces address of array as a value:

	p = <value, pointer to array 2 of array 3 of int, &arr>

`Evaluate' p:

	<object, pointer to array 2 of array 3 of int, p> =
		<value, pointer to array 2 of array 3 of int, &arr>

The types match, so the assignment is correct.  The object `p' is
given the address of `arr'.  `p++' adjusts p to skip over one
whole `array 2 of array 3 of int'.  On a byte-addressed machine, p++
adds 2*3*sizeof(int) to p.

	b. for `int (*q)[3]; q = arr;'

	q = <object, array 2 of array 3 of int, arr>

This time the object is in a value context (rhs of `=') so the rule
`object, array N of T, arr => value, pointer to T, &arr[0]' applies:

	q = <value, pointer to array 3 of int, &arr[0]>

Expand q:

	<object, pointer to array 3 of int, q> =
		<value, pointer to array 3 of int, &arr[0]>

The types match; q gets the given value.  `q++' adjusts q to skip
over one whole `array 3 of int'; on a byte-addressed machine, this
adds 3*sizeof(int).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

chris@mimsy.umd.edu (Chris Torek) (01/10/90)

>>   float arrf[3] = {1.2,2.3,3.4};
>>   arrf;            /*evaluates to pointer to float according to K&R*/

[note that this is because of a special case: `arrf' is an <object,
array N=3 of T=float, arrf> where a value is needed.]

In article <CHUCKP.90Jan9132735@halley.ncr-fc.FtCollins.NCR.com>
chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) writes:
>When declaring/defining arrf, space is allocated for a pointer to the array
>_in the symbol table_, _not_ in the actual object code.

This is bogus.  The C language is not necessarily compiled, and even
if it is, the language itself does not claim anything about a `symbol
table'.  If a compiler emits correct code purely by divine guidance and
has no memory at all, it can still be a C compiler.

Again, `float *p; p = arrf;' puts `arrf' in value context, so a C
compiler is obliged to generate whatever code it takes to store the
address of the first (0'th) element of the array in the object `p'.
This address is stored in whatever representation is used for the
type `float *'.

In New (ANSI) C, `float (*q)[3]; q = &arrf;' has `arrf' in an object
context, not a value context; the `&' applies, and a C compiler is
obliged to generate whatever code it takes to store the address of
the entire array in the object `q'.  This address is stored in whatever
representation is used for the type `float (*)[3]'.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) (01/11/90)

]In article <24521@gryphon.COM> bagpiper@pnet02.gryphon.com (Michael Hunter) writes:
]chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) writes:
]>In article <2378@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
]>>   Am I wrong in the inference from K&R that:

]>>   float arrf[3] = {1.2,2.3,3.4};
]>>   arrf;            /*evaluates to pointer to float according to K&R*/

]>When declaring/defining arrf, space is allocated for a pointer to the array
]>_in the symbol table_, _not_ in the actual object code.  (i.e.  this address
]>may not manifest itself in the object code at all if never referenced)

]>> &arrf; /*evaluates to pointer to pointer to float (my inference)*/

]>So now, as I understand it, you're asking for a pointer to something that
]>exists in the symbol table that is often stripped from the final version of
]>programs.

]This must be done by the linker or some postprocessor of the
]executable...otherwise how could the compiler tell that a object is not
]referenced in some other module (even static functions or varaibles via
]pointers.)

Granted.  But the question remains: "What is the compiler supposed to do when
the programmer askes for a pointer to something in the symbol table?"

Personally I like the idea of hysterical electronic laughter, but was asking
what ANSI had specified.

Before someone else does, let me flame myself:
#pragma FLAME_ON
Please add to the list of the most commonly deserved answers to the most
commonly asked C questions instructions for obtaining the ANSI C standard.
(i.e. how to get TFM)
#pragma FLAME_ON

Question: Wouldn't it be _really neat_ if the actual ANSI C standard were
commonly available in CS related bookstores?

#include <std/disclaimer.h>
--
	   Chuck Phillips -- chuckp%bach.ncr-fc.FtCollins.NCR.COM

chris@mimsy.umd.edu (Chris Torek) (01/11/90)

In article <CHUCKP.90Jan10103228@halley.ncr-fc.FtCollins.NCR.com>
chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) writes:
>Granted.  But the question remains: "What is the compiler supposed to do when
>the programmer askes for a pointer to something in the symbol table?"

The language does not provide a means for the programmer to do such a
thing (the language makes no statements about the internals of compilers,
or even the existance of compilers, other than to require anything that
pretends to implement C to follow some particular standard).

>Personally I like the idea of hysterical electronic laughter, but was asking
>what ANSI had specified.

I think the case in question here is supposed to be this:

 1	float arrf[3] = { 1.2, 2.3, 3.4 };
 2
 3	foo() {
 4		float **p;
 5
 6		p = &arrf;
 7	}

The question is `What is the appropriate response from a C implementation
when it is fed this code?'; the answer is `Produce a diagnostic.'  (In
other words, `hysterical electronic laughter'.)

Line 7, in particular, consists of:

  (/)	<object, pointer to pointer to float, p> =
 (//)		& <object, array 3 of float, arrf>;

The LHS of the equal sign (marked `/') is in object context, hence
remains unchanged.  The RHS (`//') is in value context, but is
complex.  The first part is a unary `&', whose target is in object
context:

	& <object, array 3 of float, arrf>

Since it *is* an object, the `&' applies.  The result is a value:

	<value, pointer to array 3 of float, &arrf>

This is a value in a value context, so it now remains unchanged.
We now have

	<object, pointer to pointer to float, p> =
		<value, pointer to array 3 of float, &arrf>;

An assignment is correct ONLY IF THE TYPES OF THE LEFT AND RIGHT
AND SIDES MATCH.  Here they do not.  A compiler must issue a
diagnostic.  This is either an error: the line is ignored, or
a warning: the compiler makes a guess as to what the programmer
intended.  Many compilers follow Stephen Johnson's lead by making
it a warning, and inserting a cast:

	<object, pointer to pointer to float, p> =
insert>	    (float **)
		<value, pointer to array 3 of float, &arrf>;

The result of this cast is machine dependent.  In order to decide
what it does, we have to be told what machine (and possibly which
implementation of the C language on that machine) is being used.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

walter@hpclwjm.HP.COM (Walter Murray) (01/12/90)

Gary L. Randolph writes:

> If this part of the answer does not seem reasonable, take it up with
> Harbison and Steele's second edition.  The statement was taken verbatim
> from page 273, section 11.6.4.

[Quoting H&S-2:  "The address operator & applied to an array yields
"pointer to array of T" or "pointer to pointer to T".]

This statement by Harbison and Steele contradicts ANSI C.  They
should not have added the part about "pointer to pointer to T".
ANSI 3.3.3.2.

> And, if that is not enough, see page 200 A7.1 of K&R2 (or read below).

> If the type of an expression or subexpression is "array of T," for
> some type T, then the value of the expression is a pointer to the
> first object in the array, and the type of the expression is altered
> to "pointer to T".

> K&R2 does not say that the above is true only for a few special cases.

Read the very next sentence:  "This conversion does not take place if
the expression is the operand of the unary & operator ... ."
This is in ANSI 3.2.2.1.

Walter Murray
----------

shaw@paralogics.UUCP (Guy Shaw) (01/12/90)

In article <2378@ektools.UUCP>, randolph@ektools.UUCP (Gary L. Randolph) writes:
> In article <21621@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
> >In article <2368@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:

> >> . . .

> >POINTERS AND ARRAYS ARE NOT NOW AND NEVER HAVE BEEN EQUIVALENT IN C.
> 
> True, but array *names* may certainly be treated as constant pointers.

When Alfred Hitchcock was being given a hard time about saying that actors are
cattle, he straightened out that bit of irresponsible misquoting:

  "I never said that actors WERE cattle, I merely said they should be TREATED
   as cattle."

Enough said.
--
-- 
Guy Shaw
Paralogics
paralogics!shaw@uunet.uu.net  or  uunet!paralogics!shaw

bph@buengc.BU.EDU (Blair P. Houghton) (01/13/90)

In article <21764@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>In article <CHUCKP.90Jan10103228@halley.ncr-fc.FtCollins.NCR.com>
>chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) writes:
>>Granted.  But the question remains: "What is the compiler supposed to do when
>>the programmer askes for a pointer to something in the symbol table?"
>
>The language does not provide a means for the programmer to do such a
>thing (the language makes no statements about the internals of compilers,
>or even the existance of compilers, other than to require anything that
>pretends to implement C to follow some particular standard).

What Chris is trying to say (though I think he's been hanging around
with Doug and Daffy too long) is:

Usually when you ask for the pointer to an array you get a
pointer to the first element of the array.  While the
symbol table will hold the compiler's copy of the address
of the beginning of the array, the data in the array
obviously can not be stored in the symbol table.

E.g.:

	type_t *aptr, a[MAXINDEX+1];

	aptr = &a;

	if ( *aptr == a[0] )
	    puts( "Will always print this." );

I can't think of anything else in the symbol table that
would need to have its address taken, except maybe function
names, struct names, etc., which also have defined meanings
when the addressof operator is applied to them.  Taking the
address of a constant is an error.

				--Blair
				  "Luckily, I'm inconstant:
				   uunet!buengc!bph."

karl@haddock.ima.isc.com (Karl Heuer) (01/13/90)

In article <5248@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>Usually when you ask for the pointer to an array you get a
>pointer to the first element of the array.

No, you get a pointer to the entire array (in ANSI C) or an error (in K&R C),
except in those pre-ANSI compilers that chose, as an extension, to make the
misinterpretation you describe (usually accompanied by a warning).

>E.g.:
>	type_t *aptr, a[MAXINDEX+1];
>	aptr = &a;

I don't know of any compiler that will accept that line without a diagnostic.

To reiterate the ANSI convention (the only one worth mentioning, since the
other behavior is really just correcting a "probably typo" for &a[0]):
	type_t (*aptr)[SIZE], a[SIZE];
	aptr = &a;
	if ( *aptr == a )
	    puts( "Will always print this." );

Note that "*aptr" and "a" are both array objects, and hence in the rvalue
context of the compare *each* will be converted to a pointer:
	if ( &(*aptr)[0] == &a[0] )

Karl W. Z. Heuer (karl@haddock.isc.com or ima!haddock!karl), The Walking Lint

chris@mimsy.umd.edu (Chris Torek) (01/13/90)

>In article <21764@mimsy.umd.edu> I wrote the usual.

In article <5248@buengc.BU.EDU> bph@buengc.BU.EDU (Blair P. Houghton) writes:
>What Chris is trying to say (though I think he's been hanging around
>with Doug and Daffy too long) is:
>
>Usually when you ask for the pointer to an array you get a
>pointer to the first element of the array.

No, nope, not even loosely speaking.  When you ask for a pointer to an
array, you get a pointer to that array (in New C) or an error (in Classic
C).

>While the symbol table will hold the compiler's copy of the address
>of the beginning of the array, the data in the array obviously can
>not be stored in the symbol table.

Each element of a symbol table in the average C compiler holds:

 - the name of a variable, function, label, etc.;
 - its type (such as `array 3 of int');
 - its scope (local, file, or global);
 - its duration (static or automatic); and
 - a *RULE* for finding the object (if any).

The last is *not*, repeat *NOT*, the `address of the array'.  In particular,
if the array is local to a block, such as with

	f() {
		int array[10];

the array does not *have* an address until run-time.  The rule for finding
this array is typically something like `subtract 48 from frame pointer
register' or `add 16 to stack pointer register'.

>E.g.:
>
>	type_t *aptr, a[MAXINDEX+1];
>
>	aptr = &a;

. . . is a type mismatch error, as I have just explained at least three
times in the last week.  Use `aptr = &a[0]' or `aptr = a'.

>	if ( *aptr == a[0] )
>	    puts( "Will always print this." );

More or less.

>I can't think of anything else in the symbol table that
>would need to have its address taken, except maybe function
>names, struct names, etc., which also have defined meanings
>when the addressof operator is applied to them.  Taking the
>address of a constant is an error.

The last sentence is correct.  The address-of operator may be applied
only to objects.  (Note that `*aptr' is an object.)  In addition, in
Classic C, the address-of operator may not be applied to objects that
are arrays.  The ANSI C committee removed this (essentially pointless)
restriction.

One more time: if you have a book that purports to explain the C language,
and it says `arrays are the same as pointers', cross that part out.  If
it does not say `a pointer points to zero or more objects', add that in.
In particular, given

	type_t *aptr, array[30];

you can make `aptr' point to (the first of) 30 objects by writing:

	aptr = &array[0];

or

	aptr = array;

The latter works because in value contexts (but only in value contexts),
an object of type `array N of T' becomes a value of type `pointer to T'
that points to the first (0'th) element of that array.  If your book
does not say this, add it as well.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

bph@buengc.BU.EDU (Blair P. Houghton) (01/14/90)

In article <15638@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <5248@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>>Usually when you ask for the pointer to an array you get a
>>pointer to the first element of the array.
>
>No, you get a pointer to the entire array (in ANSI C) or an error (in K&R C),
>except in those pre-ANSI compilers that chose, as an extension, to make the
>misinterpretation you describe (usually accompanied by a warning).

"those...that chose" happens to describe all the compilers I can find
(three different pre-ansi, one ansi-I-think (it's gcc with the ansi
switch turned on...)).

>>E.g.:
>>	type_t *aptr, a[MAXINDEX+1];
>>	aptr = &a;
>
>I don't know of any compiler that will accept that line without a diagnostic.

Yup.  Bug-ola.  S'what I get for posting examples instead of code...

To explain why `aptr = &a' instead of `aptr = a', I was
trying to answer the "what do you get when you _ask_ for a
pointer to an array" rather than "how do you make a pointer
to an array" (which is a non sequitur).

>To reiterate the ANSI convention (the only one worth mentioning, since the
>other behavior is really just correcting a "probably typo" for &a[0]):

Nope.  I'd do it `aptr = a' or `aptr = &a[0]', depending on what
I intended to mean by it; if I was going to do `aptr = &a[1]'
a line or two later, I'd use the latter form.

Oh, and the solution, on all the compilers I can get ahold of
(being an empiricist when it's efficacious) will accept and
work as intended if we just replace the offending line with

	aptr = (type_t *) &a;

Whether this is a hack in the compilers or a deliberate misreading
of the std or ambiguously allowed by the std I don't know.

>	type_t (*aptr)[SIZE], a[SIZE];
>	aptr = &a;

Classic C gives a "can't take the address of this object" warning.
ANSI C is ominously quiet.
The program thus produced runs as desired, however, regardless of
the compiler's pedigree.

>Note that "*aptr" and "a" are both array objects, and hence in the rvalue
>context of the compare *each* will be converted to a pointer:
>	if ( &(*aptr)[0] == &a[0] )

				--Blair
				  "Now there's a thought."

ark@alice.UUCP (Andrew Koenig) (01/15/90)

In article <5260@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes:

> Oh, and the solution, on all the compilers I can get ahold of
> (being an empiricist when it's efficacious) will accept and
> work as intended if we just replace the offending line with

> 	aptr = (type_t *) &a;

> Whether this is a hack in the compilers or a deliberate misreading
> of the std or ambiguously allowed by the std I don't know.

It's a hack.

Recall that this is in the context of

	type_t *aptr, a[MAXINDEX+1];

That is, `a' is an array of MAXINDEX+1 values of type `type_t' and
`aptr' is a pointer to a type_t.  Then `&a' is of type
`pointer to array of MAXINDEX+1 type_t', otherwise written
`type_t(*)[MAXINDEX+1]', and converting that to `type_t *' is
an unsafe cast.  Instead, in ANSI C, you can write

	aptr = *(&a);

which is, of course, precisely equivalent to

	aptr = a;

Here, you're dereferencing &a again to obtain the array itself,
which is then silently converted to a pointer to its initial element.

Another way to write this is:

	type_t (*array_ptr)[MAXINDEX+1] = &a;
	aptr = *array_ptr;

That is, declare an array pointer variable and explicitly store
the array pointer there, then dereference it and implicitly convert
it to an element pointer.
-- 
				--Andrew Koenig
				  ark@europa.att.com

karl@haddock.ima.isc.com (Karl Heuer) (01/17/90)

In article <5260@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>In article <15638@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>>In article <5248@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>>>Usually when you ask for the pointer to an array you get a
>>>pointer to the first element of the array.
>>
>>No, you get a pointer to the entire array (in ANSI C) or an error (in K&R
>>C), except in those pre-ANSI compilers that chose, as an extension, to make
>>the misinterpretation you describe (usually accompanied by a warning).
>
>"those...that chose" happens to describe all the compilers I can find
>(three different pre-ansi, one ansi-I-think (it's gcc with the ansi
>switch turned on...)).

As I said, in ANSI C you get a pointer to the entire array.  You claim that
gcc gives you a pointer to the first element instead.  I don't think you've
tested it in a way that would distinguish those two results.  A pointer to an
entire array and a pointer to the first element, after being converted to a
common type, will compare equal.

Exercise: design a program that will print "ANSI" if the compiler defines &a
as I described, or "non-ANSI" if it simply ignores the &.  Compile it with gcc
and at least one pre-ANSI compiler, and tell us what you find.

Karl W. Z. Heuer (karl@haddock.isc.com or ima!haddock!karl), The Walking Lint
(I'll skip the rest of the article, since I don't think we're talking on the
same wavelength yet.)