473,386 Members | 1,785 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Implicit addition of const qualifiers

-----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!
Thanks,
Roger

- --
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8 <http://mailcrypt.sourceforge.net/>

iD8DBQFCzGCVVcFcaSW/uEgRArUGAKDoU72gbXjcIj+vTl3p6G1HD0B5lACgvwxV
ih47/4KIkBWTCY8lVM5nndk=
=v5Ep
-----END PGP SIGNATURE-----
Nov 15 '05 #1
8 2549
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.
Nov 15 '05 #2
Me
> 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: *snip* 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?
This is taken directly from the C++ standard:

[Note: if a program could assign a pointer of type T** to a pointer of
type const T** (that is, if line //1 below was allowed), a program
could inadvertently modify a const object (as it is done on line //2).
For example,
int main () {
const char c = 'c';
char * pc;
const char ** pcc = & pc ; // 1: not allowed
*pcc = & c;
*pc = 'C'; // 2: modifies a const object
}
-end note]
Adding
(const char * const *) casts all over the place doesn't really improve
code readability, even if it does give me const correctness!


Don't do that. The types are considered not to be compatible and if you
access it, you break aliasing rules (which GCC is strict about and can
generate code that gives you incorrect results or crashes). More info
about aliasing in plain English:

http://mail-index.netbsd.org/tech-ke...8/11/0001.html

Nov 15 '05 #3
On Thu, 07 Jul 2005 00:47:06 +0100, Christian Bau wrote:

....
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
OK
char** -> const char** is unsafe
const char** -> char** is safe
These are both unsafe.
char*** -> const char*** is safe
const char*** -> char*** is unsafe


As are these. C allows

char ** -> char *const *
char *** -> char **const *

I believe C++ also allows:

char *** -> char *const *const *
char *** -> const char *const *const *
char (*)[N] -> const char (*)[N]

I.e. if you add const all "higher" intermediate levels must also be const
qualified. For whatever reasons the C committee decided not to support
this, which is a pity.

Lawrence

Nov 15 '05 #4
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Lawrence Kirby <lk****@netactive.co.uk> writes:
On Thu, 07 Jul 2005 00:47:06 +0100, Christian Bau wrote:

...
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
OK
char** -> const char** is unsafe
const char** -> char** is safe


These are both unsafe.


For the top example, I have a pointer to pointer-to-char being cast
to pointer to pointer-to-const-char. I don't see how any addition of
const qualifiers makes it unsafe. I now can't modify the char through
the pointer (**p = 'c'), but I fail to see how there are other issues.
char*** -> const char*** is safe
const char*** -> char*** is unsafe


As are these. C allows


I'm afraid I still fail to see why the first is unsafe.
char ** -> char *const *
char *** -> char **const *

I believe C++ also allows:

char *** -> char *const *const *
char *** -> const char *const *const *
char (*)[N] -> const char (*)[N]

I.e. if you add const all "higher" intermediate levels must also be const
qualified. For whatever reasons the C committee decided not to support
this, which is a pity.


In my code, I have "char *type[]" passed to functions as "char **".
This is an argv-like array of pointers-to-strings. Most of the
functions don't modify the pointed-to objects. They might iterate
through them, copy them, etc.. In this case, I'm not modifying the
string array nor the strings themselves, so "const char * const *"
would be ideal, so it's obvious to the caller that it's read-only.
It's also useful to indicate functions that would not be safe to use
with truly const arrays of strings.

My only problem here is the compiler warning about the conversion
(char ** -> const char * const *), but I'm afraid I still don't
understand why this it, even with your examples.
Regards,
Roger

- --
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8 <http://mailcrypt.sourceforge.net/>

iD8DBQFC2p5yVcFcaSW/uEgRAp/dAJwP54PPxBLIpDIai+pUkbxH63UJsACdFgov
8/LnVcHfJrihmxLIo9y7Tpo=
=bvV6
-----END PGP SIGNATURE-----
Nov 15 '05 #5
On Sun, 17 Jul 2005 19:07:48 +0100, Roger Leigh wrote:
Lawrence Kirby <lk****@netactive.co.uk> writes:
On Thu, 07 Jul 2005 00:47:06 +0100, Christian Bau wrote:
<snip>
const char** -> char** is safe
These are both unsafe.


For the top example, I have a pointer to pointer-to-char being cast
to pointer to pointer-to-const-char. I don't see how any addition of
const qualifiers makes it unsafe. I now can't modify the char through
the pointer (**p = 'c'), but I fail to see how there are other issues.


You didn't examine Me's example closely enough. Here it is again with
commentary:

int main (void) {
const char c = 'c'; /* we declare c to be const-protected */
char * pc;
const char ** pcc = & pc ; /* we assign the address of a non-const
* char pointer to a doubly indirected const
* char pointer. You want want this cast
* conversion to be automatic */
*pcc = & c; /* now we assign the address of our
* const-protected variable c to the pointer
* that pcc points to, which is pc.
* i.e. this line is equivalent to pc = &c
* which plainly should not be allowed because
* it removes the const-protection from c. */
*pc = 'C'; /* now we can assign to our supposedly
* const-protected c variable by dereferencing
* our non-const pc pointer. Why? Because the
* cast from char ** to const char ** was
* automatically allowed. */
}
char*** -> const char*** is safe
const char*** -> char*** is unsafe


As are these. C allows


I'm afraid I still fail to see why the first is unsafe.


By extension for the same reason as Me's example shows.

<snip>
In my code, I have "char *type[]" passed to functions as "char **".
This is an argv-like array of pointers-to-strings. Most of the
functions don't modify the pointed-to objects. They might iterate
through them, copy them, etc.. In this case, I'm not modifying the
string array nor the strings themselves, so "const char * const *"
would be ideal, so it's obvious to the caller that it's read-only.
It's also useful to indicate functions that would not be safe to use
with truly const arrays of strings.

My only problem here is the compiler warning about the conversion
(char ** -> const char * const *), but I'm afraid I still don't
understand why this it, even with your examples.


That one semantically is still safe, since it would disallow the
problem assignment *pcc = &c in the above example.

It is not allowed by C though, I don't know why.

Nov 15 '05 #6
Netocrat <ne******@dodo.com.au> writes:
On Sun, 17 Jul 2005 19:07:48 +0100, Roger Leigh wrote:

For the top example, I have a pointer to pointer-to-char being cast
to pointer to pointer-to-const-char. I don't see how any addition of
const qualifiers makes it unsafe. I now can't modify the char through
the pointer (**p = 'c'), but I fail to see how there are other issues.


You didn't examine Me's example closely enough. Here it is again with
commentary:


Thanks, that makes much more sense.
--
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
Nov 15 '05 #7
On Mon, 18 Jul 2005 18:20:03 +1000, Netocrat <ne******@dodo.com.au>
wrote:

<snip>
My only problem here is the compiler warning about the conversion
(char ** -> const char * const *), but I'm afraid I still don't
understand why this it, even with your examples.


That one semantically is still safe, since it would disallow the
problem assignment *pcc = &c in the above example.

It is not allowed by C though, I don't know why.


AIUI because it was simpler to think of, explain, and prove safe, the
single simple rule T * -> qualified T * . Remember that qualification
itself was new in C90 and there wasn't widespread experience with
implementation and use. C++, with the benefit of hindsight and perhaps
more time to analyze, does allow it.

- David.Thompson1 at worldnet.att.net
Nov 15 '05 #8
Dave Thompson <da*************@worldnet.att.net> wrote:

AIUI because it was simpler to think of, explain, and prove safe, the
single simple rule T * -> qualified T * . Remember that qualification
itself was new in C90 and there wasn't widespread experience with
implementation and use. C++, with the benefit of hindsight and perhaps
more time to analyze, does allow it.


Correct. Unfortunately, the C++ standard describes the language
sufficiently differently from the way C did that it isn't possible to
just pick up the words from the C++ standard and plug them into the C
standard. C also adopted the additional "restrict" qualifier, which
will require a revision of the rules since it doesn't seem to behave the
same as const and volatile.

-Larry Jones

Is it too much to ask for an occasional token gesture of appreciation?!
-- Calvin
Nov 15 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Romulus Mare | last post by:
How can I avoid writting and maintaining the same code in the two operator implementation below? I know that in the minimal example below, the implementation is trivial, but I found this type of...
2
by: joe | last post by:
hi, after reading some articles and faq, i want to clarify myself what's correct(conform to standard) and what's not? or what should be correct but it isn't simply because compilers don't...
17
by: DanielESFA | last post by:
Hey guys :) This is a bit of a funny one... We're four guys working on the same project, everybody using KDevelop and g++ on Linux. Three of us are using Mandrake, with g++ 3.4.3 and 3.4.1....
16
by: hzmonte | last post by:
Correct me if I am wrong, declaring formal parameters of functions as const, if they should not be/is not changed, has 2 benefits; 1. It tells the program that calls this function that the...
10
by: d3x0xr | last post by:
---- Section 1 ---- ------ x.c int main( void ) { char **a; char const *const *b; b = a; // line(9)
0
by: d3x0xr | last post by:
Heh, spelled out in black and white even :) Const is useles... do NOT follow the path of considering any data consatant, because in time, you will have references to it that C does not handle,...
0
by: wellingj | last post by:
A little back ground on what I'm trying to do: I'm making a generic weighted graph class (vertexes and edges althought I don't call them that) to implement some pathfinding algorithms like A* and D*....
4
by: lovecreatesbea... | last post by:
Gcc only gives out a warning: `assignment discards qualifiers from pointer target type' against code such as following: $ type a.c int main(void) { const char *pc; char *p = pc;
39
by: Leonardo Korndorfer | last post by:
Hi, I'm litle confused by the const modifier, particularly when use const char* or char*. Some dude over here said it should be const char when you dont modify it content inside the function, I...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.