pass "double *const *" ptr to fn expecting "const double *const *" 
Author Message
 pass "double *const *" ptr to fn expecting "const double *const *"

[[Disclaimer:  This is _not_ a homework problem, it's an abstraction
of a genuine programming problem I've encountered in my reserch.]]

Suppose I have a set of arrays of doubles, and an array of pointers
to the start of these arrays:
        /* assume function  make_array()  returns suitable pointers */
        double *foo_x = make_array(N);
        double *foo_y = make_array(N);
        double *foo_z = make_array(N);
        double *const foo[3] = {foo_x, foo_y, foo_z};

Now consider a function
        double vector_sum(int V, int N, const double *const src_arrays[]);

This function promises not to change either the array of pointers,
or any of the double values they point to.  Ok, so far so good.

Now suppose I want to pass  foo  to this function:
        double sum = vector_sum(3, N, foo);
gcc -Wall complains that I'm
        passing arg 3 of `vector_sum' from incompatible pointer type
The problem is that  foo  has type  double *const *  whereas the
function expects an argument of type  const double *const * , and
C only allows adding const qualifiers in assignment at the top level
of a declaration, not recursively.  [Cf question 11.10 of the comp.lang.c
FAQ at   http://www.*-*-*.com/ ~scs/C-faq/top.html  .]

So, what to do?

There are several fairly-obvious ways to "fix" the problem (pass  foo
to the function), none of which particularly appeal to me:

- Just ignore the warning:  In my experience  gcc -Wall  doesn't cry
  wolf very often, so I'm disinclined to ignore it here.  Indeed, it's
  right in this example, trying to pass  foo  is indeed breaking one
  of C's rules.  And if I just ignore the warning, then I have the
  extra hassle of filtering out the 25 or so similar warnings which
  will occur in my actual project, so as to not miss other "genuine"
  gcc warnings.  So I don't like this solution.

- Change the function's prototype/definition to
        double vector_sum(int V, int N, double *const src_arrays[]);
  But this is wrong:  It implies that the function might modify the
  double values, which (since I wrote the code) I know to be false.
  Since the function actually only reads those values, IMHO it's
  good style to state that explicitly in its prototype.  So I don't
  like this "solution" either.

- Roughly the same, add a suitable const qualifier to foo's definition.
  This fails because I also pass  foo  to other functions which *do*
  modify the pointed-to doubles.

- Explicitly cast  foo  when I call the function:
        double sum = vector_sum(3, N, (const double *const *) foo);
  This is ugly and error-prone.  Yes, I can hide the cast inside a macro
        #define CONST_VECTOR_PTR(x)     (const double *const *) x
  but it's still ugly.

- The same idea, but factor the cast out of the (many) function calls,
  by defining another pointer  cfoo  which is the result of this cast, i.e.
        const double *const *const cfoo = (const double *const *) foo;
        double sum = vector_sum(3, N, cfoo);
  The problem is that this means that I need to "decorate" the code
  to record at the calling site which pointer needs passing.  In my
  actual project I have similar functions which take   double *const *
  pointers (and indeed other functions which take some parmaeters of
  one type and some of the other), and I'd rather not have to explicitly
  mark this distinction at the (many) call sites.

My question is, is there an elegant way to treat this problem in
(standard) C?  Would C++ be any different here (I think not)?

My definition of "elegant" in this context includes
- The function prototype still makes it explicit that the function
  will not modify either the pointers or the pointed-to doubles.
- No explicit "decoration" needed at the calling site to mark which
  calls are passing pointers to functions expecting  const double *const * ,
  and which to function expecting   double *const * .

--

    http://www.*-*-*.com/ ~jthorn/home.html
   Universitaet Wien (Vienna, Austria) / Institut fuer Theoretische Physik
   "The first strike in the American Colonies was in 1776 in Philadelphia,
    when [...] carpenters demanded a 72-hour week." -- Anatole Beck
--



Sun, 02 Dec 2001 03:00:00 GMT  
 pass "double *const *" ptr to fn expecting "const double *const *"

: Suppose I have a set of arrays of doubles, and an array of pointers
: to the start of these arrays:
:       /* assume function  make_array()  returns suitable pointers */
:       double *foo_x = make_array(N);
:       double *foo_y = make_array(N);
:       double *foo_z = make_array(N);
:       double *const foo[3] = {foo_x, foo_y, foo_z};

: Now consider a function
:       double vector_sum(int V, int N, const double *const src_arrays[]);

: This function promises not to change either the array of pointers,
: or any of the double values they point to.  Ok, so far so good.

: Now suppose I want to pass  foo  to this function:
:       double sum = vector_sum(3, N, foo);
: gcc -Wall complains that I'm
:       passing arg 3 of `vector_sum' from incompatible pointer type
: The problem is that  foo  has type  double *const *  whereas the
: function expects an argument of type  const double *const * , and
: C only allows adding const qualifiers in assignment at the top level
: of a declaration, not recursively.  [Cf question 11.10 of the comp.lang.c
: FAQ at  http://www.eskimo.com/~scs/C-faq/top.html  .]

I will assume that the faq gives an example of why it is unsafe.

: So, what to do?

: - Explicitly cast  foo  when I call the function:
:       double sum = vector_sum(3, N, (const double *const *) foo);
:   This is ugly and error-prone.  Yes, I can hide the cast inside a macro
:       #define CONST_VECTOR_PTR(x)     (const double *const *) x
:   but it's still ugly.

Great!  It is ugly (moreso in C++).  You know that you are doing
something which is generally unsafe.  It should look ugly and be
grepable.  It is safe in your case and that is what casts are for.
It allows you to tell the compiler that you know what you are doing
and not be prevented just because it might be unsafe for some other
use.

: My question is, is there an elegant way to treat this problem in
: (standard) C?  Would C++ be any different here (I think not)?

C++ is different in being less restrictive, but that would not help
you here.

double const** p;
double const* const* q = p;

That is accepted by C++ but not C.  They both reject what you are
doing.

: My definition of "elegant" in this context includes

Violating the basic rules of the language.  No way it can be elegant,
it must be UGLY.  Consider it documentation and don't hide it.

John
--



Tue, 04 Dec 2001 03:00:00 GMT  
 pass "double *const *" ptr to fn expecting "const double *const *"
Groovy hepcat Jonathan Thornburg was jivin' on Wed, 16 Jun 1999
19:39:02 GMT in comp.lang.c.moderated.
pass "double *const *" ptr to fn expecting "const double *const *"'s a
cool scene! Dig it!

Quote:
>Suppose I have a set of arrays of doubles, and an array of pointers
>to the start of these arrays:
>    /* assume function  make_array()  returns suitable pointers */
>    double *foo_x = make_array(N);
>    double *foo_y = make_array(N);
>    double *foo_z = make_array(N);
>    double *const foo[3] = {foo_x, foo_y, foo_z};

  I know this is some time after you posted, but since noone else
seems to have pointed this out I thought I'd better say something...
  You can't do what you have tried above in ANSI/ISO/IEC C. Your array
initialisers must be constant expressions. It works for you because
this is an extention provided by your compiler. Try the -pedantic (I
think) switch, and you might see a difference.
--

----- Dig the EVEN NEWER, MORE IMPROVED news sig!! -----

-------------- Shaggy was here! ---------------
    http://aardvark.apana.org.au/~phaywood/
============= Ain't I'm a dawg!! ==============
--



Mon, 10 Dec 2001 03:00:00 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. Style question: "int const" versus "const int"

2. "I don't like const"

3. 2 meanings of "const"

4. How constant is "const"?

5. Why not "const char *strerror(int);"??

6. CComBSTR into a "const char *"

7. "static const int" and case expression

8. "const" and the compiler

9. "const" globals omitted from global list

10. internal compiler error with "const"

11. "const"-problem

12. Use of "const" in X includes

 

 
Powered by phpBB® Forum Software