const keyword and pointer

Y

Yoshi

Hello,

I encountered following code when I was reading man page of qsort.

In the function compstringp, it casts p1 and p2 to ( char * const * ).
I re-read the C-Faq and still don't understand what it means.

Does ( char * const * ) means, cast to "pointer to const pointer to
char"? Does it make sense to cast this way ?


static int
cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference */

return strcmp(* (char * const *) p1, * (char * const *) p2);
}

int
main(int argc, char *argv[])
{
int j;

assert(argc > 1);

qsort(&argv[1], argc - 1, sizeof(argv[1]), cmpstringp);

for (j = 1; j < argc; j++)
puts(argv[j]);
exit(EXIT_SUCCESS);
}


Thank you
 
B

Ben Bacarisse

Yoshi said:
I encountered following code when I was reading man page of qsort.

In the function compstringp, it casts p1 and p2 to ( char * const * ).
I re-read the C-Faq and still don't understand what it means.

Does ( char * const * ) means, cast to "pointer to const pointer to
char"?
Yes.

Does it make sense to cast this way ?

Yes. qsort passes a pair of pointers to the compare function. Each
one points to one of the things being compared. argv is an array of
pointers to char (the initial character of each argument string) so
qsort passes values of type char **.

As for the const, the pointers that cmpstringp gets are const pointers
so we cast to char * const * rather than unadorned char **.
static int
cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference */

return strcmp(* (char * const *) p1, * (char * const *) p2);
}

int
main(int argc, char *argv[])
{
int j;

assert(argc > 1);

qsort(&argv[1], argc - 1, sizeof(argv[1]), cmpstringp);

for (j = 1; j < argc; j++)
puts(argv[j]);
exit(EXIT_SUCCESS);
}

I leave the above for context.
 
M

mohangupta13

Yes.  qsort passes a pair of pointers to the compare function.  Each
one points to one of the things being compared.  argv is an array of
pointers to char (the initial character of each argument string) so
qsort passes values of type char **.

As for the const, the pointers that cmpstringp gets are const pointers
so we cast to char * const * rather than unadorned char **.
what i also fail to understand is the above line ,
strcmp expects const char * so why we don't cast them to that , why
has the cast *(char* const *) done ??
int
main(int argc, char *argv[])
{
    int j;
    assert(argc > 1);
    qsort(&argv[1], argc - 1, sizeof(argv[1]), cmpstringp);
    for (j = 1; j < argc; j++)
        puts(argv[j]);
    exit(EXIT_SUCCESS);
}

I leave the above for context.
 
B

Ben Bacarisse

what i also fail to understand is the above line ,
strcmp expects const char * so why we don't cast them to that , why
has the cast *(char* const *) done ??

You can cast to const char * const * if you like, but there is little
point. After the * operation, the value being passed to strcmp is of
type char * which can be passed to a function expecting const char *
with no problems.

<snip>
 
M

mohangupta13

You can cast to const char * const * if you like, but there is little
point.  After the * operation, the value being passed to strcmp is of
type char * which can be passed to a function expecting const char *
with no problems.
if the ultimate thing that is being passed in of type char* then why
are so many casts used in the first place ,
just use
return strcmp( (const char*) p1 ,(const char*) p2);
 
B

Ben Bacarisse

mohangupta13 said:
if the ultimate thing that is being passed in of type char* then why
are so many casts used in the first place ,
just use
return strcmp( (const char*) p1 ,(const char*) p2);

Those parameters are of the right type but the wrong values. p1 and
p2 don't point at chars. They point to char pointers:

+------+ +-------+
p1 | ---|------------------->| ---|------->"abc"
+------+ +-------+
| ---|------->"def"
+------+ +-------+
p2 | ---|------------------->| ---|------->"ghi"
+------+ +-------+
 
Y

Yoshi

Yes.  qsort passes a pair of pointers to the compare function.  Each
one points to one of the things being compared.  argv is an array of
pointers to char (the initial character of each argument string) so
qsort passes values of type char **.

As for the const, the pointers that cmpstringp gets are const pointers
so we cast to char * const * rather than unadorned char **.

Thank you for your answer, but why not simply cast to (const char **)
then?
when it is dereferenced, (const char **) becomes (const char*), which
matches strcmp prototype, and if (char *const *) is dereferenced, if
will become (char *const), which does not matches prototype.

Furthermore, I wonder why compiler does not complain even if I passed
simply char *, not const char*, whereas strcmp's prototype shows it
takes const char*?

--
Yoshi



static int
cmpstringp(const void *p1, const void *p2)
{
    /* The actual arguments to this function are "pointers to
       pointers to char", but strcmp(3) arguments are "pointers
       to char", hence the following cast plus dereference */
    return strcmp(* (char * const *) p1, * (char * const *) p2);
}
int
main(int argc, char *argv[])
{
    int j;
    assert(argc > 1);
    qsort(&argv[1], argc - 1, sizeof(argv[1]), cmpstringp);
    for (j = 1; j < argc; j++)
        puts(argv[j]);
    exit(EXIT_SUCCESS);
}

I leave the above for context.
 
B

Ben Bacarisse

Yoshi said:
Thank you for your answer, but why not simply cast to (const char **)
then?

No reason other than you might get a message that you are removing
const-ness with a cast. In some sense, converting void const * to T
const * is more "correct" but there is nothing wrong with omitting the
const. Note that none of this has anything to do with the const in
your suggestion: whether we cast to const char ** or char ** does not
matter here, we are still removing the const from the void *.
when it is dereferenced, (const char **) becomes (const char*), which
matches strcmp prototype, and if (char *const *) is dereferenced, if
will become (char *const), which does not matches prototype.

"Matching" is not what matters here. The rules are subtle and I don't
really want to go find them all and quote them.

Whether a thing itself is const or not does not matter, so when passing
an argument char * const and char * are the same, and...
Furthermore, I wonder why compiler does not complain even if I passed
simply char *, not const char*, whereas strcmp's prototype shows it
takes const char*?

.... you can always add const-ness to the thing pointed to so a char *
argument is permitted when the function expects const char *.
 
Y

Yoshi

No reason other than you might get a message that you are removing
const-ness with a cast.  In some sense, converting void const * to T
const * is more "correct" but there is nothing wrong with omitting the
const.  Note that none of this has anything to do with the const in
your suggestion: whether we cast to const char ** or char ** does not
matter here, we are still removing the const from the void *.

But it seems removing const from the void * does not matter also here.

"Matching" is not what matters here.  The rules are subtle and I don't
really want to go find them all and quote them.

Whether a thing itself is const or not does not matter, so when passing
an argument char * const and char * are the same, and...

Found related part, so using pointer to T for const pointer to T is
ok, but not other cases..so we don't have to care the mismatch
here...now I understand, Thank you.
http://c-faq.com/ansi/constmismatch.html
 
Y

Yoshi

No reason other than you might get a message that you are removing
const-ness with a cast.  In some sense, converting void const * to T
const * is more "correct" but there is nothing wrong with omitting the
const.  Note that none of this has anything to do with the const in
your suggestion: whether we cast to const char ** or char ** does not
matter here, we are still removing the const from the void *.

But it seems removing const from the void * does not matter also here.

"Matching" is not what matters here.  The rules are subtle and I don't
really want to go find them all and quote them.

Whether a thing itself is const or not does not matter, so when passing
an argument char * const and char * are the same, and...

Found related part, so using pointer to T for const pointer to T is
ok, but not other cases..so we don't have to care the mismatch
here...now I understand, Thank you.
http://c-faq.com/ansi/constmismatch.html
 
Y

Yoshi

No reason other than you might get a message that you are removing
const-ness with a cast.  In some sense, converting void const * to T
const * is more "correct" but there is nothing wrong with omitting the
const.  Note that none of this has anything to do with the const in
your suggestion: whether we cast to const char ** or char ** does not
matter here, we are still removing the const from the void *.

But it seems removing const from the void * does not matter also here.

"Matching" is not what matters here.  The rules are subtle and I don't
really want to go find them all and quote them.

Whether a thing itself is const or not does not matter, so when passing
an argument char * const and char * are the same, and...

Found related part, so using pointer to T for const pointer to T is
ok, but not other cases..so we don't have to care the mismatch
here...now I understand, Thank you.
http://c-faq.com/ansi/constmismatch.html
 
Y

Yoshi

No reason other than you might get a message that you are removing
const-ness with a cast.  In some sense, converting void const * to T
const * is more "correct" but there is nothing wrong with omitting the
const.  Note that none of this has anything to do with the const in
your suggestion: whether we cast to const char ** or char ** does not
matter here, we are still removing the const from the void *.

But it seems removing const from the void * does not matter also here.

"Matching" is not what matters here.  The rules are subtle and I don't
really want to go find them all and quote them.

Whether a thing itself is const or not does not matter, so when passing
an argument char * const and char * are the same, and...

Found related part, so using pointer to T for const pointer to T is
ok, but not other cases..so we don't have to care the mismatch
here...now I understand, Thank you.
http://c-faq.com/ansi/constmismatch.html
 
Y

Yoshi

No reason other than you might get a message that you are removing
const-ness with a cast.  In some sense, converting void const * to T
const * is more "correct" but there is nothing wrong with omitting the
const.  Note that none of this has anything to do with the const in
your suggestion: whether we cast to const char ** or char ** does not
matter here, we are still removing the const from the void *.

But it seems removing const from the void * does not matter also here.

"Matching" is not what matters here.  The rules are subtle and I don't
really want to go find them all and quote them.

Whether a thing itself is const or not does not matter, so when passing
an argument char * const and char * are the same, and...

Found related part, so using pointer to T for const pointer to T is
ok, but not other cases..so we don't have to care the mismatch
here...now I understand, Thank you.
http://c-faq.com/ansi/constmismatch.html
 
B

Ben Bacarisse

Yoshi said:
But it seems removing const from the void * does not matter also
here.

The trouble is the word "matter". It matters to me, but not to you
and maybe not to your compiler. I like to be told when I cast away
const because that is often significant, so with the compiler flags I
use I get a warning if don't cast to a type that has const between the
two stars.

<snip>
 
Y

Yoshi

The trouble is the word "matter".  It matters to me, but not to you
and maybe not to your compiler.  I like to be told when I cast away
const because that is often significant, so with the compiler flags I
use I get a warning if don't cast to a type that has const between the
two stars.

OK, I guess I should be careful about it even if it works without
const, after all, I did not understand it before, and now, I've got
it.
Thanks anyway.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top