[comp.std.c] const arrays in prototypes

pmontgom@euphemia.math.ucla.edu (Peter Montgomery) (05/26/90)

/*
	When declaring a pointer to a function, careful use of const 
lets us distinguish whether the function is allowed to modify the 
pointer and/or the data.  For example
*/
void proc1 (  int       *p1,	/* non-const pointer to non-const int */
 	const int       *p2,	/* non-const pointer to     const int */
              int *const p3,	/*     const pointer to non-const int */
	const int *const p4)    /*     const pointer to     const int */
{
    p1++;
    p2++;
    p3++;	/* illegal modification of pointer */
    p4++;	/* illegal modification of pointer */
    *p1 = 1;
    *p2 = 2;	/* illegal modification of data    */
    *p3 = 3;
    *p4 = 4;	/* illegal modification of data    */
}
/*
	As desired, gcc 1.37.1 issues warnings for the four lines
marked "illegal".  

	Suppose instead that I am passing an array argument.  If I 
put "const" before the declaration, then I am stating that the data 
will not be modified.  How do I specify that the pointer to the array
will not be altered within the subroutine?  For example,
*/

void DISALLOW(const int mat[2][2])
{
    mat++;		/* I want to forbid this usage.		       */	
    mat[0][1] = 4;	/* Gcc 1.37.1 properly warns about this line.  */
}

--
--------
        Peter Montgomery
        pmontgom@MATH.UCLA.EDU 
	Department of Mathematics, UCLA, Los Angeles, CA 90024

zhu@crabcake.cs.jhu.edu (Benjamin Zhu) (05/27/90)

In article <2781@sunset.MATH.UCLA.EDU> pmontgom@euphemia.math.ucla.edu (Peter Montgomery) writes:
>[lots of stuffs deleted]
>	Suppose instead that I am passing an array argument.  If I 
>put "const" before the declaration, then I am stating that the data 
>will not be modified.  How do I specify that the pointer to the array
>will not be altered within the subroutine?  For example,
>*/
>
>void DISALLOW(const int mat[2][2])
 
	Use the following prototype instead:

	void DISALLOW(const int ** const mat)

	It's fairly self-explanatory. Add const before mat, indicating the
	the pointer is also constant.

>{
>    mat++;		/* I want to forbid this usage.		       */	
>    mat[0][1] = 4;	/* Gcc 1.37.1 properly warns about this line.  */
>}
>
>--
>--------
>        Peter Montgomery
>        pmontgom@MATH.UCLA.EDU 
>	Department of Mathematics, UCLA, Los Angeles, CA 90024

Benjamin Zhu

+=========================================================================+
+Disclaimer:								  +
+	I do not represent Johns Hopkins, Johns Hopkins does not	  +
+	represent me either.						  +
+==========================================================================

norvell@csri.toronto.edu (Theo Norvell) (05/27/90)

In article <1356@crabcake> zhu@crabcake.cs.jhu.edu (Benjamin Zhu) writes:
>In article <2781@sunset.MATH.UCLA.EDU> pmontgom@euphemia.math.ucla.edu (Peter Montgomery) writes:
>>	Suppose instead that I am passing an array argument.  If I 
>>put "const" before the declaration, then I am stating that the data 
>>will not be modified.  How do I specify that the pointer to the array
>>will not be altered within the subroutine?
> 
>	Use the following prototype instead:
>
>	void DISALLOW(const int ** const mat)
>
>	It's fairly self-explanatory. Add const before mat, indicating the
>	the pointer is also constant.
>
>Benjamin Zhu

Perhaps you mean
	void DISALLOW( const int (*const mat)[2] )
But this is UGLY.

Is the following a solution?
	typedef const int const_matrix[2][2] ;
	...
	void DISALLOW( const const_matrix mat )
If not, I'm sure someone will point out why.

Theo Norvell

karl@haddock.ima.isc.com (Karl Heuer) (05/27/90)

>In article <2781@sunset.MATH.UCLA.EDU> pmontgom@euphemia.math.ucla.edu (Peter Montgomery) writes:
>>Suppose instead that I am passing an array argument.

You can't.  So I'll assume you meant "suppose I am passing a pointer and using
the pointer-argument syntax that resembles an array declaration."

>>How do I specify that the pointer to the array will not be altered within
>>the subroutine?

You can't.  Use the equivalent pointer syntax instead, then put the const
keyword in the right place.

>>For example, 
>>	void DISALLOW(const int mat[2][2]) {...}

The misdeclaration "int mat[2][2]" is silently converted to "int (*mat)[2]",
so what you want is
	void DISALLOW(int (*const mat)[2]) {...}
or, if you intend both the pointer and the data to be non-modifiable,
	void DISALLOW(int const (*const mat)[2]) {...}
(the first "const" may also appear before the type).

In article <1356@crabcake> zhu@crabcake.cs.jhu.edu (Benjamin Zhu) writes:
>Use the following prototype instead:
>	void DISALLOW(const int ** const mat)

Sorry, that's not equivalent.  You've changed the semantics of his function.

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

zhu@crabcake.cs.jhu.edu (Benjamin Zhu) (05/27/90)

In article <1990May26.164834.4211@jarvis.csri.toronto.edu> norvell@csri.toronto.edu (Theo Norvell) writes:
>In article <1356@crabcake> zhu@crabcake.cs.jhu.edu (Benjamin Zhu) writes:
>>In article <2781@sunset.MATH.UCLA.EDU> pmontgom@euphemia.math.ucla.edu (Peter Montgomery) writes:
>>>	Suppose instead that I am passing an array argument.  If I 
>>>put "const" before the declaration, then I am stating that the data 
>>>will not be modified.  How do I specify that the pointer to the array
>>>will not be altered within the subroutine?
>> 
>>	Use the following prototype instead:
>>
>>	void DISALLOW(const int ** const mat)
>>
>>	It's fairly self-explanatory. Add const before mat, indicating that
>>	the pointer is also constant.
>>
>>Benjamin Zhu
>
>Perhaps you mean
>	void DISALLOW( const int (*const mat)[2] )
>But this is UGLY.
>

	OK, this one would work, though someone might think it is ugly.

>Is the following a solution?
>	typedef const int const_matrix[2][2] ;
>	...
>	void DISALLOW( const const_matrix mat )
>If not, I'm sure someone will point out why.
>
	Nope. In this case, "const" has been used twice, i.e., it
	is duplicatedly declared, which I believe is illegal in
	Ansi stardard.  Moreover, I fail to notice any semantical
	difference between "const_matrix" and "const const_matrix".
	Maybe you mean something else?

>Theo Norvell

Benjamin Zhu

+=========================================================================+
+Disclaimer:								  +
+	I do not represent Johns Hopkins, Johns Hopkins does not	  +
+	represent me either.						  +
+==========================================================================

diamond@tkou02.enet.dec.com (diamond@tkovoa) (05/29/90)

In article <1990May26.164834.4211@jarvis.csri.toronto.edu> norvell@csri.toronto.edu (Theo Norvell) writes:

>>Perhaps you mean
>>	void DISALLOW( const int (*const mat)[2] )
>>But this is UGLY.

It's as ugly as any other solution, and as ugly as most of C.

>>Is the following a solution?
>>	typedef const int const_matrix[2][2] ;
>>	...
>>	void DISALLOW( const const_matrix mat )
>>If not, I'm sure someone will point out why.

This is also valid.
But you know the net.  Even if it's a solution, we can still trust
someone to point out why it isn't.  ;-)
In article <1359@crabcake> zhu@crabcake.cs.jhu.edu (Benjamin Zhu) writes:
>	Nope. In this case, "const" has been used twice, i.e., it
>	is duplicatedly declared, which I believe is illegal in
>	Ansi stardard.  Moreover, I fail to notice any semantical
>	difference between "const_matrix" and "const const_matrix".
>	Maybe you mean something else?
Mr. Zhu, you have gotten this one wrong twice.  Looks like you should
take a vacation from answering questions, until you're more alert.

typedef const int const_matrix[2][2] ;
means that a variable of type const_matrix will have constant elements.
void DISALLOW( const const_matrix mat )
means that the pointer "mat" is a constant pointer.
So the result is a constant pointer to constant elements.
The two "const"s do not duplicate each other.

-- 
Norman Diamond, Nihon DEC     diamond@tkou02.enet.dec.com
Proposed group comp.networks.load-reduction:  send your "yes" vote to /dev/null.

zhu@crabcake.cs.jhu.edu (Benjamin Zhu) (05/29/90)

In article <1745@tkou02.enet.dec.com> diamond@tkou02.enet.dec.com (diamond@tkovoa) writes:
>In article <1990May26.164834.4211@jarvis.csri.toronto.edu> norvell@csri.toronto.edu (Theo Norvell) writes:
>
>>>Perhaps you mean
>>>	void DISALLOW( const int (*const mat)[2] )
>>>But this is UGLY.
>
>It's as ugly as any other solution, and as ugly as most of C.
>
>>>Is the following a solution?
>>>	typedef const int const_matrix[2][2] ;
>>>	...
>>>	void DISALLOW( const const_matrix mat )
>>>If not, I'm sure someone will point out why.
>
>This is also valid.
>But you know the net.  Even if it's a solution, we can still trust
>someone to point out why it isn't.  ;-)
>In article <1359@crabcake> zhu@crabcake.cs.jhu.edu (Benjamin Zhu) writes:
>>	Nope. In this case, "const" has been used twice, i.e., it
>>	is duplicatedly declared, which I believe is illegal in
>>	Ansi stardard.  Moreover, I fail to notice any semantical
>>	difference between "const_matrix" and "const const_matrix".
>>	Maybe you mean something else?
>Mr. Zhu, you have gotten this one wrong twice.  Looks like you should
>take a vacation from answering questions, until you're more alert.

	Wait a second. Let's see what you comment.

>
>typedef const int const_matrix[2][2] ;
>means that a variable of type const_matrix will have constant elements.
>void DISALLOW( const const_matrix mat )
>means that the pointer "mat" is a constant pointer.
>So the result is a constant pointer to constant elements.
>The two "const"s do not duplicate each other.

	No, I believe I am correct. Haven't you confused an array with
	a pointer? An array has to be treeted as a single object. So
	to define

		typedef	const int const_matrix[2][2];
		const const_matrix mat;

	is analogous to define

		typedef const int const_int;
		const const_int number;

	Of course the two const's duplicate each other. If you take
	my arguments, what's the semantical difference then? OK, if
	you insist that const duplication is allowed, then there IS
	some difference.

	I am not flaming you. Would you kindly test what you say, or
	at least check the references before you jump on someone?
>
>-- 
>Norman Diamond, Nihon DEC     diamond@tkou02.enet.dec.com
>Proposed group comp.networks.load-reduction:  send your "yes" vote to /dev/null.

Benjamin Zhu

+=========================================================================+
+Disclaimer:								  +
+	I do not represent Johns Hopkins, Johns Hopkins does not	  +
+	represent me either.						  +
+==========================================================================

diamond@tkou02.enet.dec.com (diamond@tkovoa) (05/30/90)

In article <1373@crabcake> zhu@crabcake.cs.jhu.edu (Benjamin Zhu) writes:
>In article <1745@tkou02.enet.dec.com> diamond@tkou02.enet.dec.com (diamond@tkovoa) writes:
>>In article <1990May26.164834.4211@jarvis.csri.toronto.edu> norvell@csri.toronto.edu (Theo Norvell) writes:
>>>>Is the following a solution?
>>>>	typedef const int const_matrix[2][2] ;
>>>>	void DISALLOW( const const_matrix mat )

Please note that this "mat" is a parameter.  Therefore its type is a
pointer, not an array.

ND>>... a variable of type const_matrix will have constant elements.
ND>>... the pointer "mat" is a constant pointer.
ND>>The two "const"s do not duplicate each other.

BZ>	No, I believe I am correct. Haven't you confused an array with
BZ>	a pointer? An array has to be treeted as a single object. So
BZ>	to define
BZ>		typedef	const int const_matrix[2][2];
BZ>		const const_matrix mat;
BZ>	is analogous to define
BZ>		typedef const int const_int;
BZ>		const const_int number;
BZ>	Of course the two const's duplicate each other.

This "mat" is not a parameter, so its type is indeed an array.
Yes, for arrays, these two "const"s duplicate each other.
This is a different problem from the one Mr. Norvell asked.

>	I am not flaming you. Would you kindly test what you say, or
>	at least check the references before you jump on someone?

Both Mr. Zhu and I missed what appears to be yet another bug in the
standard.  Someone asked a question via e-mail, and in attempting
to answer, I found the odd wording in the standard:
In section 3.7.1, "On entry to the function", argument values and
parameter types are adjusted.  So the type is adjusted at run time!!!!
In section 3.5.4.3, parameter types are not adjusted at all in
prototypes for function declarators!!!!

Therefore three interpretations are now necessary.  (1) should the
adjustment be done at compilation/translation/whatever time instead
of run time; (2) should adjustments also be done in declarators;
and (3) do adjustments occur before or after the outer "const" is
applied to the parameter.

-- 
Norman Diamond, Nihon DEC     diamond@tkou02.enet.dec.com
Proposed group comp.networks.load-reduction:  send your "yes" vote to /dev/null.

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/30/90)

In article <1752@tkou02.enet.dec.com> diamond@tkou02.enet.dec.com (diamond@tkovoa) writes:
>In section 3.7.1, "On entry to the function", argument values and
>parameter types are adjusted.  So the type is adjusted at run time!!!!

Of course this is dealt with at compile time, just as are other
implicit type conversions in other contexts.

>In section 3.5.4.3, parameter types are not adjusted at all in
>prototypes for function declarators!!!!

They most certainly are; from 3.5.4.3 Semantics:

	(For each parameter declared with a function or array type,
	its type for these comparisons is the one that results from
	conversion to a pointer type, as in 3.7.1.  For each
	parameter declared with qualified type, its type for these
	comparisons is the unqualified version of its declared type.)

>Therefore three interpretations are now necessary.

No interpretations are needed; the intent of the standard is clear.