In article <87************@hardknott.home.whinlatter.ukfsn.or g>,
Roger Leigh <${*******@invalid.whinlatter.ukfsn.org.invalid> wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
A lot of functions use const pointer arguments. If I have a non-const
pointer, it is transparently made const when I pass it to the
function, e.g. char * -> const char *. However, this does not appear
to work when I add another level of indirection:
void test1 (char **value)
{}
void test2 (const char **value)
{}
void test3 (const char * const *value)
{}
void test4 (char * const *value)
{}
int
main (void)
{
char **v;
test1(v);
test2(v);
test3(v);
test4(v);
return 0;
}
$ gcc -Wall -pedantic -o test1 test.c
test.c: In function Œmain¹:
test.c:19: warning: passing argument 1 of Œtest2¹ from
incompatible
pointer type
test.c:20: warning: passing argument 1 of Œtest3¹ from
incompatible pointer type
Why is this sort of conversion requiring an explicit cast? Adding
(const char * const *) casts all over the place doesn't really improve
code readability, even if it does give me const correctness!
Lets say you have a char* (points to chars that can be modified), and a
function that takes a const char* parameter (points to chars that cannot
be modified). The language allows an automatic cast, because no harm
will be done: All that happens is that the function cannot easily modify
the chars, even though it would be ok (from the callers point of view)
to modify them. It is also obvious that in the opposite situation, an
automatic cast shouldn't be allowed by the C language: Such a cast would
mean that the function could modify chars that are actually const; a
very dangerous thing to do.
Now what you have is a char** (points to pointers to modifiable chars),
and the function takes an argument const char** (points to pointers to
unmodifiable chars). Now lets say I have an array somewhere
static const array [10];
If I have a const char**, lets say const char** p, then an assignment
*p = &array [0];
would be perfectly legal. However, if I have another pointer char** q
(note: Not const char**) then if the language allowed me to write
*q = &array [0];
that would be a very dangerous thing: I cannot use *p to modify a char,
but I can use *q, for example (*q) [2] = '\0'; . That is why the
compiler doesn't allow the assignment *q = &array [0] - allowing this
assignment would mean that I could modify a const char without using a
cast. That cannot be allowed.
Now to your problem: You have a pointer char** q. Your function takes an
argument const char** p. If you could pass the char** q to the function
without a cast, then the assignment
*p = &array [0];
could be performed within the function, which would do effectively the
same thing as writing
*q = &array [0];
outside the function, which as we have seen must not be allowed. The
automatic conversion from char* to const char* is safe - it doesn't let
you do anything that you couldn't do without the conversion. The
automatic conversion from char** to const char** is NOT safe: Such a
conversion would allow you to store a const char* where a (non const)
char* is expected, and consequently to modify a const char which must
not be allowed.
If you think carefully about it, you will find that the following
conversions are safe resp. unsafe (and therefore are allowed /
disallowed to happen automatically):
char* -> const char* is safe
const char* -> char* is unsafe
char** -> const char** is unsafe
const char** -> char** is safe
char*** -> const char*** is safe
const char*** -> char*** is unsafe
and so on.