Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why does clang 10.0.1 (FreeBSD 12.2) warn about this?

31 views
Skip to first unread message

Winston

unread,
Feb 6, 2021, 10:53:50 PM2/6/21
to
Passing char *p to a function foo(const char *p) is common.

Passing const char *p to a function foo(char *p) gets a warning about
discarding const, as one would expect.

Maybe I'm just not thinking clearly at the moment, but I don't see why
passing char *p using foo(&p) to the function foo(const char **pp) causes
this warning:

[...].c: warning: passing 'char **' to parameter of type 'const char **'
discards qualifiers in nested pointer types
[-Wincompatible-pointer-types-discards-qualifiers]

[...].h: note: passing argument to parameter 'pp' here
extern char * foo(const char **pp);

Is this a bug, or what am I missing? Thanks,
-WBE

The Doctor

unread,
Feb 7, 2021, 8:38:38 AM2/7/21
to
In article <ydr1lsa...@UBEblock.psr.com>,
Is this a port or a newly made application?
--
Member - Liberal International This is doctor@@nl2k.ab.ca Ici doctor@@nl2k.ab.ca
Yahweh, Queen & country!Never Satan President Republic!Beware AntiChrist rising!
Look at Psalms 14 and 53 on Atheism https://www.empire.kred/ROOTNK?t=94a1f39b
NFLD on 13 Feb vote Liberal !

Winston

unread,
Feb 8, 2021, 2:02:25 AM2/8/21
to
I previously posted:
>>Passing char *p to a function foo(const char *p) is common.

>>Passing const char *p to a function foo(char *p) gets a warning about
>>discarding const, as one would expect.

>>Maybe I'm just not thinking clearly at the moment, but I don't see why
>>passing char *p using foo(&p) to the function foo(const char **pp) causes
>>this warning:

>>[...].c: warning: passing 'char **' to parameter of type 'const char **'
>> discards qualifiers in nested pointer types
>> [-Wincompatible-pointer-types-discards-qualifiers]

>>[...].h: note: passing argument to parameter 'pp' here
>>extern char * foo(const char **pp);

>>Is this a bug, or what am I missing? Thanks,

to which doc...@doctor.nl2k.ab.ca (The Doctor) asked:
> Is this a port or a newly made application?

It was code I'd just written, not something distributed by FreeBSD.
-WBE

Paul Floyd

unread,
Feb 8, 2021, 4:54:47 AM2/8/21
to
It's a question of indirection. No indirection and one level of
indirection will always be considered for implicit conversion. The
second level (and any further levels) aren't automatically considered.
See the entry on implicit conversion on cppreference.com

A+
Paul
--
Paul Floyd http://paulf.free.fr

Winston

unread,
Feb 8, 2021, 1:03:02 PM2/8/21
to
I originally posted:
>> Maybe I'm just not thinking clearly at the moment, but I don't see why
>> passing char *p using foo(&p) to the function foo(const char **pp) causes
>> this warning:

>> [...].c: warning: passing 'char **' to parameter of type 'const char **'
>> discards qualifiers in nested pointer types
>> [-Wincompatible-pointer-types-discards-qualifiers]

>> [...].h: note: passing argument to parameter 'pp' here
>> extern char * foo(const char **pp);

Paul Floyd <ro...@127.0.0.1> kindly replied:
> It's a question of indirection. No indirection and one level of
> indirection will always be considered for implicit conversion. The
> second level (and any further levels) aren't automatically considered.

OK, thanks. That would explain WHY.

As to WHAT, I'll contend that a warning message that says "discards
qualifiers" in such a case (the same as the compiler warns for (const
char *) passed to a (char *) argument) is misleading.

> See the entry on implicit conversion on cppreference.com

[To others reading this thread: the word "implicit" did not appear on
https://cpreference.com/, and using the search box there to search for
"implicit conversion" suprisingly found no results. After following a
few likely links related to C (not C++), I ended up at:

https://en.cppreference.com/w/c/language/conversion

talking about conversions "as if by assignment" and "implicit conversion
semantics". I saw nothing there about conversion depth, but at the
bottom of that page, under "See also", it linked to a description of C++
implicit conversions. I followed that link to:

https://en.cppreference.com/w/cpp/language/implicit_conversion

which said that the addition of const/volatile qualifiers at arbitrary
depths ARE acceptable, but that when there's effectively an array of
unknown bounds involved, additional const qualifiers are needed. It
gave a C++ example that pretty directly matched my original question:

char** p = 0;
const char** p1 = p; // error: level 2 more cv-qualified but level 1 is not const
const char* const * p2 = p; // OK: level 2 more cv-qualified and const added at level 1

I'm a bit surprised at this end result, but at least now I know about
it. Thanks, Paul.
-WBE

[I still think "discards qualifiers" is misleading.
"Requires qualifiers" for this case would be more accurate.]

Mikhail T.

unread,
Feb 11, 2021, 11:09:01 PM2/11/21
to
On 08.02.21 13:02, Winston wrote:
> OK, thanks. That would explain WHY.
>
> As to WHAT, I'll contend that a warning message that says "discards
> qualifiers" in such a case (the same as the compiler warns for (const
> char *) passed to a (char *) argument) is misleading.

This is not an operating system topic. This is a compiler topic...

-mi

Jens Schweikhardt

unread,
Feb 13, 2021, 6:46:11 AM2/13/21
to
Winston <w...@ubeblock.psr.com.invalid> wrote
in <ydr1lsa...@UBEblock.psr.com>:
# Passing char *p to a function foo(const char *p) is common.
#
# Passing const char *p to a function foo(char *p) gets a warning about
# discarding const, as one would expect.
#
# Maybe I'm just not thinking clearly at the moment, but I don't see why
# passing char *p using foo(&p) to the function foo(const char **pp) causes
# this warning:
#
# [...].c: warning: passing 'char **' to parameter of type 'const char **'
# discards qualifiers in nested pointer types
# [-Wincompatible-pointer-types-discards-qualifiers]
#
# [...].h: note: passing argument to parameter 'pp' here
# extern char * foo(const char **pp);
#
# Is this a bug, or what am I missing?

This looks like a C FAQ: http://c-faq.com/ansi/constmismatch.html

comp.lang.c FAQ list · Question 11.10

Q: Why can't I pass a char ** to a function which expects a const char **?

A: You can use a pointer-to-T (for any type T) where a
pointer-to-const-T is expected. However, the rule (an explicit
exception) which permits slight mismatches in qualified pointer types is
not applied recursively, but only at the top level. (const char ** is
pointer-to-pointer-to-const-char, and the exception therefore does not
apply.)

The reason that you cannot assign a char ** value to a const char **
pointer is somewhat obscure. Given that the const qualifier exists at
all, the compiler would like to help you keep your promises not to
modify const values. That's why you can assign a char * to a const char
*, but not the other way around: it's clearly safe to ``add'' const-ness
to a simple pointer, but it would be dangerous to take it away. However,
suppose you performed the following more complicated series of
assignments:

const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */

In line 3, we assign a char ** to a const char **. (The compiler should
complain.) In line 4, we assign a const char * to a const char *; this
is clearly legal. In line 5, we modify what a char * points to--this is
supposed to be legal. However, p1 ends up pointing to c, which is const.
This came about in line 4, because *p2 was really p1. This was set up in
line 3, which is an assignment of a form that is disallowed, and this is
exactly why line 3 is disallowed.

Assigning a char ** to a const char ** (as in line 3, and in the
original question) is not immediately dangerous. But it sets up a
situation in which p2's promise--that the ultimately-pointed-to value
won't be modified--cannot be kept.

(C++ has more complicated rules for assigning const-qualified pointers
which let you make more kinds of assignments without incurring warnings,
but still protect against inadvertent attempts to modify const values.
C++ would still not allow assigning a char ** to a const char **, but it
would let you get away with assigning a char ** to a const char * const
*.)

In C, if you must assign or pass pointers which have qualifier
mismatches at other than the first level of indirection, you must use
explicit casts (e.g. (const char **) in this case), although as always,
the need for such a cast may indicate a deeper problem which the cast
doesn't really fix.

References: ISO Sec. 6.1.2.6, Sec. 6.3.16.1, Sec. 6.5.3
H&S Sec. 7.9.1 pp. 221-2

Regards,

Jens
--
Jens Schweikhardt http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)

Winston

unread,
Feb 13, 2021, 8:37:29 AM2/13/21
to
I originally asked (in part):
>> ... I don't see why passing char *p using foo(&p) to the function
>> foo(const char **pp) causes this warning:

>> [...].c: warning: passing 'char **' to parameter of type 'const char **'
>> discards qualifiers in nested pointer types
>> [-Wincompatible-pointer-types-discards-qualifiers]

>> [...].h: note: passing argument to parameter 'pp' here
>> extern char * foo(const char **pp);

>> Is this a bug, or what am I missing?

to which Jens Schweikhardt <use...@schweikhardt.net> kindly replied:
> This looks like a C FAQ: http://c-faq.com/ansi/constmismatch.html

Hadn't heard of that FAQ before. I'll add it to my references
collection. :)

> comp.lang.c FAQ list · Question 11.10
>
> Q: Why can't I pass a char ** to a function which expects a const char **?

The exact case in question, and for C, not C++. Nice!

> (C++ has more complicated rules for assigning const-qualified pointers

Indeed, and that was where I ended up when I followed the other C
reference. That led to an alternative explanation of why, but the one
you posted sticks to C in explaining why.

> In C, if you must assign or pass pointers which have qualifier
> mismatches at other than the first level of indirection, you must use
> explicit casts (e.g. (const char **) in this case), although as always,
> the need for such a cast may indicate a deeper problem which the cast
> doesn't really fix.

Thanks, Jens!
-WBE

[I still think warning "discards qualifiers" reads too much like
(const char *) passed to (char *) and is thus misleading in a case like
this which superficially appears similar, even if it's potentially true
as the FAQ example showed.]
0 new messages