const array arguments 
Author Message
 const array arguments

This concerns compiler warnings when passing non-const-qualified
arguments to functions with const-qualified parameters.  Several
compilers complain about "incompatible pointer types", due to the
parameter's const qualifier, if the argument is an array of more than
one dimension or a pointer to a pointer.

I suspect that this has been discussed here before, but I've Googled
around a bit and failed to find much.

Consider the following test program.  main() declares a matrix and
initializes its values.  It passes it to print_matrix(), which
prints the values.  The matrix is not const in main(), but is
const in print_matrix() -- and I want the prototype to say so.

pf and ppf are to illustrate variations on the theme, using pointer
rather than array syntax in the arguments and parameters.

The SGI f77 compiler issues the following warnings.  Sun f77, and
g77, behave similarly:

   cc: WARNING Line = 25
     Argument of type "float **" is incompatible with parameter of type
             "const float **".

           print_ppf    (ppf) ;
                         ^

   cc: WARNING Line = 27
     Argument of type "float (*)[3]" is incompatible with parameter of
             type "const float (*)[3]".

           print_matrix (matrix) ;
                         ^

Notice there is no warning for passing "float *" to "const float *".

There is also no warning for passing "float[3]" to "const float[3]",
which is essentially the same situation (since the array is passed
as a pointer).

I don't understand why there should be warnings for the "float **"
and "float (*)[3]" forms.  As far as I can tell from reading the
ANSI standard, the "const" qualifier on the argument is simply a
guarantee that the function won't attempt to modify the value
through that pointer.

The warning seems to me like a compiler bug.  But it's so common ...

Thanks for insights.  Please refer me to specific clauses in the
ANSI standard.  (I have ANSI/ISO 9899-1990).

   ---   Ted Hall

/*------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>

   void print_pf     (const float *pf) ;
   void print_ppf    (const float **ppf) ;
   void print_vec    (const float vec[3]) ;
   void print_matrix (const float matrix[3][3]) ;

   int main (void)
   {
      float   matrix[3][3] ;
      float   *pf ;
      float   **ppf ;
      int     i, j ;

      for (i = 0 ; i < 3 ; i++)
         for (j = 0 ; j < 3 ; j++)
            matrix[i][j] = (i == j) ? 1. : 0. ;

      pf  = matrix[0] ;
      ppf = &pf ;

      print_pf     (pf) ;
      print_ppf    (ppf) ;
      print_vec    (matrix[0]) ;
      print_matrix (matrix) ;

      return (EXIT_SUCCESS) ;
   }

   void print_pf (const float *pf)
   {
      printf ("pf     = [%g %g %g]\n", pf[0], pf[1], pf[2]) ;
   }

   void print_ppf (const float **ppf)
   {
      const float   *pf ;
      pf = *ppf ;
      printf ("*ppf   = [%g %g %g]\n", pf[0], pf[1], pf[2]) ;
   }

   void print_vec (const float vec[3])
   {
      printf ("vec    = [%g %g %g]\n", vec[0], vec[1], vec[2]) ;
   }

   void print_matrix (const float matrix[3][3])
   {
      int   i ;
      printf ("matrix =\n") ;
      for (i = 0 ; i < 3 ; i++)
         printf ("   [%g %g %g]\n",
            matrix[i][0], matrix[i][1], matrix[i][2]) ;
   }
--



Mon, 10 Oct 2005 03:33:03 GMT  
 const array arguments

Quote:

>      Argument of type "float **" is incompatible with parameter of type
>              "const float **".

Which is true.  The short answer is that really-constant constness
is not what is normally wanted for a pointer parameter, but rather
will-not-write constness, which occurs only at the *first* level of
indirection.  (There are difficult technical issues involved with
trying to specify this at deeper levels or indirection, so we didn't.)
--



Wed, 12 Oct 2005 01:35:41 GMT  
 const array arguments
On 23 Apr 2003 19:33:03 GMT, Theodore W. Hall said:

Quote:
> This concerns compiler warnings when passing non-const-qualified
> arguments to functions with const-qualified parameters.  Several
> compilers complain about "incompatible pointer types", due to the
> parameter's const qualifier, if the argument is an array of more than
> one dimension or a pointer to a pointer.

> I suspect that this has been discussed here before, but I've Googled
> around a bit and failed to find much.

This is covered pretty well in Peter van der Linden's book (Deep
C Secrets) - in brief,

1) Passing arguments to a function works like assignment -
basically the variable in the argument list of the function gets
assigned the variable in the calling function.

So if we have
int fun(const char **str)
{
...

Quote:
}

...
int main()
{
  char **test;
  int ret;
  ret = fun(test);
  ...

Quote:
}

the call to fun essentially does "str = test".

2) Types are compatible for assignment if
 a) The lhs of the assignment is the same type as the rhs, and
 the rhs has at least all the qualifiers of the lhs.
 b) They are pointers to types specified in a

So the question boils down to whether we can assign a char ** to
a const char **. To see why we can't, you have to see why
assigning a char * to a const char * is fine...

A const char * is a pointer to a const-qualified char. Following
rule b, we can assign a variable which is a pointer to the same
type, or to the same type with fewer qualifications (in brief).
So assigning a pointer to a char is fine.

However, a const char ** is a pointer to a pointer to a const
qualified char. And a char ** is a pointer to a pointer to a
char. And pointer to char is not the same as pointer to const
char. They don't just differ in qualifications, they point at
things which differ in qualifications.

Quote:
> Consider the following test program.  main() declares a matrix and
> initializes its values.  It passes it to print_matrix(), which
> prints the values.  The matrix is not const in main(), but is
> const in print_matrix() -- and I wantthe prototype to say so.

Actually, with a const at the start, the matrix isn't const at
all - only its elements are. What you seem to want is a char **
const. This makes the base pointer const, while allowing the
elements (and the row) to be modified. Or maybe char * const
* const (which makes the pointer, and the pointer-to-pointer,
const, but leaves teh elements of teh matrix changeable.

Quote:
> Thanks for insights.  Please refer me to specific clauses in the
> ANSI standard.  (I have ANSI/ISO 9899-1990).

Specific clauses... I'm afraid I don't have the compiler handy at
the moment. It's a comp.lang.C FAQ -
http://www.eskimo.com/~scs/C-faq/q11.10.html

Cheers,
Dave.

--
                David Neary,
        E-Mail: bolsh at gimp dot org
   Work e-mail: d dot neary at phenix dot fr
CV: http://www.redbrick.dcu.ie/~bolsh/CV/CV.html
--



Wed, 12 Oct 2005 01:36:09 GMT  
 const array arguments
As luck would have it, the periodic posting of the FAQ showed up here
a couple of hours after I posted my question.  I followed the
"feedback" link for FAQ 11.10, and got a very helpful response from
Steve Summit.

If a (char **) Rvalue is assigned to a (const char **) Lvalue, it
sets up the possibility of an alias that can violate the "const"
qualifier.  Consider this:

      const char c = 'x';
      char *p1;
      const char **p2 = &p1;  /* so, *p2 = p1   */
      *p2 = &c;               /* so, p1  = &c   */
      *p1 = 'X';              /* so, c   = 'X'  */

The 3rd line is disallowed, in order to prevent the 4th and 5th.

Quote:

> > Consider the following test program.  main() declares a matrix
> > and initializes its values.  It passes it to print_matrix(),
> > which prints the values.  The matrix is not const in main(), but
> > is const in print_matrix() -- and I want the prototype to say so.

> Actually, with a const at the start, the matrix isn't const at
> all - only its elements are.

Yes, the Standard points that out.  I wouldn't know how else to
interpret it except as a matrix of const elements.

Quote:
> What you seem to want is a char **const.  This makes the base
> pointer const, while allowing the elements (and the row) to be
> modified. Or maybe char * const* const (which makes the pointer,
> and the pointer-to-pointer, const, but leaves the elements of
> the matrix changeable.

Well, no, actually.  In main(), I want a 2-dimensional matrix, or
rather, an array of arrays.  A pointer to a pointer is something
else.

   float   matrix[3][3] ;

The print_matrix() parameter is then a pointer to an array.

   float   (*matrix)[3] ;   /* not float *matrix[3] */
                            /* not float **matrix   */

print_matrix() doesn't change the array elements.  I would like
the prototype to say so, so that main /could/ pass a "const",
without /requiring/ it to pass a "const".

Quote:
>From the example at the top of this message, I see the problem

with

   (const float **) = (float **)

but so far, I haven't been able to concoct a simlar problem with

   (const float (*)[3]) = (float (*)[3])

I'm not clever enough, or not devious enough, to see how to
violate the "const" without invoking another level of indirection
"**".

Well, I don't really mean to beat this to death.  I accept that
I need to either omit the "const" on the left, or explictly cast
"const" into the right.

Thanks for responding.

--------

Ted Hall
--



Sat, 22 Oct 2005 11:59:32 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. const arguments or const member methods

2. Array of const pointers to const variable.

3. problem with array of const pointers to const data

4. Clean way to const-cast arrays of arrays?

5. Help: inline char const* const& max(char const* const &a, char const* const &b)

6. const in function arguments

7. Q: const pointers as arguments

8. const arguments

9. const in function argument list

10. Const class in template arguments

11. use CONST for function arguments

12. Question about array initializers, const

 

 
Powered by phpBB® Forum Software