const , and valid converstions of pointers thereto

D

d3x0xr

---- Section 1 ----

------
x.c

int main( void )
{
char **a;
char const *const *b;
b = a; // line(9)
}
------

wpp386 x.c

x.c(9): Warning! W1178: Type qualifier mismatch
x.c(9): Note! N2003: source conversion type is 'char const *const *'
x.c(9): Note! N2004: target conversion type is 'char **'

Okay this is the error, when I went through and cleaned up all the
warnings of passing (char **) as (const char **) parameters in other
compilers (gcc, MSVC), by converting function parameters to (char const
*const *), I STILL had warnings in watcom. This warning should please
to go away[engrish].

(though I still think that if the context is variable data passed to a
process expecting constant data, even if not all levels of indirection
are constant, it should be a compatible conversion, but am proven wrong
by C++ compilers)



----
Cut - ignore after this point.

Please do flog me if I dare misspell or mispunctuate.

In the beginning there is char, which is synonymous for purposes of this
conversation as byte, the plural of which is bytes.

All plural references may be assumed as preferably at least one, but
often more than one.

char c;

c is a variable character.

char const cc;
-or- const char cc;

c is a constant character.

char *s;

a variable pointer which points to a variable character;

char const *s;
-or- const char *s;

a variable pointer which points to a constant character.

char * const s;

A constant pointer which points to a variable character.

char const * const s;
-or- const char * const s;

a constant pointer which points to a constant character;

char * * l;

a variable pointer which points to a variable pointer which points to a
variable character.

char const * * l;
-or- const char * *l;

a variable pointer which points to a variable pointer which points to a
constant character.

char * const * l;

a variable pointer which points to a constant pointer which points to a
variable character;

char * * const l;

a constant pointer which points to a variable pointer which points to a
variable character;

char const * const * s;
-or- const char * const * s;

a variable pointer which points to a constant pointer which points to a
constant character.

char const * * const s;
-or- const char * * const s;

a constant pointer which points to a variable pointer which points to a
constant character.

char const * const * const s;
-or- const char * const * const s;

a constant pointer which points to a constant pointer which points to a
constant character.


One may assume that any code which requires a constant character may be
passed a variable character, with consideration that the implementation
is a single thread, and that the user of the constant data will
compelete before the data will be changed.

A more modern compiler might offer an option of declaring a variable
with volatile characteristics, such that the variable is assumed to be
able to change before a given process completes.

Most all modern compilers, and probably even lint processesors provide
no warning for converting a (char *) to a (const char *), that is if you
will recall, treating a variable character as a constant, immutable
character. Providing, even enforcing, that the process operating on the
data will not modify the data itself.

passing any such reference of non constant data to a constant data
process should not require a warning.


(const char **) = (char **) does not merit a warning, given that (const
char *) = (char *) does not.


-----------------
Some actual output from compilers - this is the program.

(Oops, this demonstrates the extra warnings in converting from (char **)
to (char const * const *)

---
int main( void )
{ char **a; // line (2)
const char *const* b; // line (3)
char *xa; // line (4)
const char *xb; // line (5)
int *xia; // line (6)
const int *xib; // line (7)
b = a; // line (8)
a = b; // line (9)
xa=xb; // line (10)
xb=xa; // line (11)
xia=xib; // line (12)
xib=xia; // line (13)
return 0; // line (14)
}

(msvc compiling as C)
[line](9) : error C2440: '=' : cannot convert from 'const char *const *
' to 'char ** '
Conversion loses qualifiers
[line](10) : error C2440: '=' : cannot convert from 'const char *' to
'char *'
Conversion loses qualifiers
[line](12) : error C2440: '=' : cannot convert from 'const int *' to
'int *'
Conversion loses qualifiers

(msvc compiling as C++)
m:\tmp\x.cpp(9) : error C2440: '=' : cannot convert from 'const char
*const * ' to 'char ** '
Conversion loses qualifiers
m:\tmp\x.cpp(10) : error C2440: '=' : cannot convert from 'const char *'
to 'char *'
Conversion loses qualifiers
m:\tmp\x.cpp(12) : error C2440: '=' : cannot convert from 'const int *'
to 'int *'
Conversion loses qualifiers

(gcc compiling as C)
x.c: In function 'main':
x.c:8: warning: assignment from incompatible pointer type
x.c:9: warning: assignment from incompatible pointer type
x.c:10: warning: assignment discards qualifiers from pointer target
type
x.c:12: warning: assignment discards qualifiers from pointer target
type

(g++ compiling as c++)
x.c: In function 'int main()':
x.c:9: error: invalid conversion from 'const char* const*' to 'char**'
x.c:10: error: invalid conversion from 'const char*' to 'char*'
x.c:12: error: invalid conversion from 'const int*' to 'int*'

(wcc386)
Open Watcom C32 Optimizing Compiler Version 1.5
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
x.c(8): Warning! W1178: Type qualifier mismatch
x.c(8): Note! N2003: source conversion type is 'char **'
x.c(8): Note! N2004: target conversion type is 'char const *const *'
x.c(9): Warning! W1178: Type qualifier mismatch
x.c(9): Note! N2003: source conversion type is 'char const *const *'
x.c(9): Note! N2004: target conversion type is 'char **'
x.c(10): Warning! W1178: Type qualifier mismatch
x.c(10): Note! N2003: source conversion type is 'char const *'
x.c(10): Note! N2004: target conversion type is 'char *'
x.c(12): Warning! W1178: Type qualifier mismatch
x.c(12): Note! N2003: source conversion type is 'int const *'
x.c(12): Note! N2004: target conversion type is 'int *'
x.c: 15 lines, 4 warnings, 0 errors

(wpp386)
M:\tmp>wpp386 x.c
Open Watcom C++32 Optimizing Compiler Version 1.5
Portions Copyright (c) 1989-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
x.c(9): Error! E246: col(3) left expression is not a pointer to a
constant object
x.c(9): Note! N717: col(3) left operand type is 'char * * (lvalue)'
x.c(9): Note! N718: col(3) right operand type is 'char const * const *'
x.c(10): Error! E246: col(3) left expression is not a pointer to a
constant object
x.c(10): Note! N717: col(3) left operand type is 'char * (lvalue)'
x.c(10): Note! N718: col(3) right operand type is 'char const *'
x.c(12): Error! E246: col(4) left expression is not a pointer to a
constant object
x.c(12): Note! N717: col(4) left operand type is 'int * (lvalue)'
x.c(12): Note! N718: col(4) right operand type is 'int const *'
x.c: 15 lines, no warnings, 3 errors



------

So in conclusion,

line 8 is not a warning or error in any C++ compiler.
nor ls 11 or 13;
-----------------------------------------------
---- section 2 ----
 
R

Richard Heathfield

d3x0xr said:
---- Section 1 ----

------
x.c

int main( void )
{
char **a;
char const *const *b;
b = a; // line(9)
}

Consider:

char foo = 'F';
char bar = 'B';
char *baz = &foo;
char **quux = &baz;
char const * const * eric;

eric = quux; /* erroneous, and equivalent to your code */

The compiler ought to be able to know for sure, because eric is a pointer to
a const pointer to char, that *eric will not change. But because you can do
this at any time:

*quux = &bar;

it becomes possible for legal code to subvert the constness of *eric, and
the compiler won't like that even a little bit.
 
M

Michal Nazarewicz

d3x0xr said:
Richard Heathfield said:
Consider:

char foo = 'F';
char bar = 'B';
char *baz = &foo;
char **quux = &baz;
char const * const * eric;

eric = quux; /* erroneous, and equivalent to your code */

The compiler ought to be able to know for sure, because eric is a
pointer to a const pointer to char, that *eric will not change.
because you can do this at any time:

*quux = &bar;

it becomes possible for legal code to subvert the constness of
*eric, and the compiler won't like that even a little bit.

As far as I know, the only thing const means is that you (the
programmer) cannot change constant of *eric using pointer eric (since
*eric is of type const char *const; same goes for **eric). Compiler
does not care or know if the actual value can change.

If what you are saying is valid then the following would be invalid:

#v+
char foo[] = "foo";
const char *bar = foo;
#v-

because (as you put it) the compiler ought to be known for sure that
*bar will never change but indeed it can through *foo.
 
R

Richard Heathfield

Michal Nazarewicz said:

If what you are saying [about const] is valid [...]

....then I'm a Dutchman. My apologies to the OP. I shouldn't have answered
that question at all. A few years ago, I worked out the logic behind the
necessity for the C Standard to be so bitchy about constness (because
somebody at work happened to ask me a very similar question to the OP's,
and it mattered, and so I looked very closely at it), and I guess I
believed, very late last night, that I still remembered it clearly enough
to explain it. Apparently not.

CHRIS!
 
D

d3x0xr

Richard Heathfield:
d3x0xr said:


Consider:

char foo = 'F';
char bar = 'B';
char *baz = &foo;
char **quux = &baz;
char const * const * eric;

eric = quux; /* erroneous, and equivalent to your code */

Why would this not be legal, you're just adding restriction on what you
will do via eric...
The compiler ought to be able to know for sure, because eric is a pointer to
a const pointer to char, that *eric will not change. But because you can do
this at any time:

*quux = &bar;

however, the standard provides for declarations that are
const volatile int blah;

which means it will change, but it will not be changed by the variable
blah.

Again, what they tell me I have a bad interpeation of is that the const
makes it so that the data will definitly be ROM type data and not
writable, it is not such, it does mean that via the reference of
varaible XXXXX it will not be changed, it does not state that beyond the
context of XXXXX that the variable will not change.
 
B

Ben Bacarisse

Richard Heathfield said:
d3x0xr said:


Consider:

char foo = 'F';
char bar = 'B';
char *baz = &foo;
char **quux = &baz;
char const * const * eric;

eric = quux; /* erroneous, and equivalent to your code */

The compiler ought to be able to know for sure, because eric is a pointer to
a const pointer to char, that *eric will not change. But because you can do
this at any time:

*quux = &bar;

it becomes possible for legal code to subvert the constness of *eric, and
the compiler won't like that even a little bit.

This problem comes from two issues interacting:

1) The standard forbids certain dangerous conversion involving
qualified types; and
2) To make things easy the rule forbids some safe conversion like the
one give.

The rule in the standard is designed to prevent modification of a
const like this:

int main(void)
{
const char foo = 'F';
char *p;
const char **cp = (const char **)&p; // force with cast
*cp = &foo;
*p = 'B';

printf("c = %c\n", foo);
return EXIT_SUCCESS;
}

Note that the compiler wants to be able to assume the foo can't change
(and maybe more importantly the programmer wants to assume that!) but
if it allowed the assignment I forced with the cast, the const foo can
be changed, silently.

To keep things simple, the standard says:

6.3.2.3:

[2] For any qualifier q, a pointer to a non-q-qualified type may be
converted to a pointer to the q-qualified version of the type; the
values stored in the original and converted pointers shall compare
equal.

and then:

6.7.3 Type qualifiers

[9] For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type; the order of
type qualifiers within a list of specifiers or qualifiers does not
affect the specified type.

which, I think, allows common (safe) usages, forbids dangerous usages
as above but also rules out certain safe combinations involving more
than one level of indirection.
 
D

d3x0xr

my point isn't even in typecasting, no typecast operator considered, as
typecasting allows the programmer to break all rules without warning or
error.

The case is, if i start writing routines that accept const char *...

then I can definatly safely pass "blah" to it, as a const char *.

if the routine is written to take a 'char*' then there are warnings
given when converting from the const char * to the char *.

So, I modify the routines to take const char *... but then eventually I
end up with a routine that takes the address of one of these
parameters... either as a char const *const * or a char const **, both
appropriate to taking the address of a const char * to pass to the
routine.

The deeper one goes with making code correct and declaring const char *
where the code definatly does not modify the content of the string, the
more trouble one has. If I had left everything as 'char*' and left the
const off, I would not be having this discussion...

Actually, the point that started this was taking all this wonderful C
code and compiling it wilth a C++ compiler which definately FORBIDS char
* = const char *. So, the parameters had to change to have a const
modifier where const data was passed such as "xyzzy".

Then, coming back to the C compiler, I get assaulted by warnings.

Ben Bacarisse:
Richard Heathfield said:
d3x0xr said:


Consider:

char foo = 'F';
char bar = 'B';
char *baz = &foo;
char **quux = &baz;
char const * const * eric;

eric = quux; /* erroneous, and equivalent to your code */

The compiler ought to be able to know for sure, because eric is a pointer to
a const pointer to char, that *eric will not change. But because you can do
this at any time:

*quux = &bar;

it becomes possible for legal code to subvert the constness of *eric, and
the compiler won't like that even a little bit.

This problem comes from two issues interacting:

1) The standard forbids certain dangerous conversion involving
qualified types; and
2) To make things easy the rule forbids some safe conversion like the
one give.

The rule in the standard is designed to prevent modification of a
const like this:

int main(void)
{
const char foo = 'F';
char *p;
const char **cp = (const char **)&p; // force with cast
*cp = &foo;
*p = 'B';

printf("c = %c\n", foo);
return EXIT_SUCCESS;
}

Note that the compiler wants to be able to assume the foo can't change
(and maybe more importantly the programmer wants to assume that!) but
if it allowed the assignment I forced with the cast, the const foo can
be changed, silently.

To keep things simple, the standard says:

6.3.2.3:

[2] For any qualifier q, a pointer to a non-q-qualified type may be
converted to a pointer to the q-qualified version of the type; the
values stored in the original and converted pointers shall compare
equal.

and then:

6.7.3 Type qualifiers

[9] For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type; the order of
type qualifiers within a list of specifiers or qualifiers does not
affect the specified type.

which, I think, allows common (safe) usages, forbids dangerous usages
as above but also rules out certain safe combinations involving more
than one level of indirection.
 
B

Ben Bacarisse

d3x0xr said:
Ben Bacarisse:
my point isn't even in typecasting, no typecast operator considered, as
typecasting allows the programmer to break all rules without warning or
error.

I know, but I put the cast in because it is needed. I then tried to
show why the cast helps. It reminds you that what some seemingly safe
assignments are not because they would allow a const object to be
changed. I know that in your original example, this is not the case,
but the standard has opted for a simple rule that also rules out some
safe combinations.

Does anyone know how compatibility between pointers to qualified types
could have been worded to allow all safe combinations whilst ruling
out all unsafe ones?
The case is, if i start writing routines that accept const char *...

then I can definatly safely pass "blah" to it, as a const char *.

if the routine is written to take a 'char*' then there are warnings
given when converting from the const char * to the char *.

So, I modify the routines to take const char *... but then eventually I
end up with a routine that takes the address of one of these
parameters... either as a char const *const * or a char const **, both
appropriate to taking the address of a const char * to pass to the
routine.

But one of these (char const **) *must* be outlawed (or forced with a
cast) because it allows a const object to be modified. The other is
just caught in the net.
The deeper one goes with making code correct and declaring const char *
where the code definatly does not modify the content of the string, the
more trouble one has. If I had left everything as 'char*' and left the
const off, I would not be having this discussion...

But then you get no const-safety. At least this way you have to stop
and think: to pass this value here I need a cast -- is it really a
safe thing to do?
 
D

d3x0xr

Again, without typecasting. There's no safe way to write code without
getting assaulted by warnrings of undefined conditions.

Why is that? Why MUST I type cast?

I don't in C++.

I don't in gcc.



Ben Bacarisse:
Richard Heathfield said:
d3x0xr said:


Consider:

char foo = 'F';
char bar = 'B';
char *baz = &foo;
char **quux = &baz;
char const * const * eric;

eric = quux; /* erroneous, and equivalent to your code */

The compiler ought to be able to know for sure, because eric is a pointer to
a const pointer to char, that *eric will not change. But because you can do
this at any time:

*quux = &bar;

it becomes possible for legal code to subvert the constness of *eric, and
the compiler won't like that even a little bit.

This problem comes from two issues interacting:

1) The standard forbids certain dangerous conversion involving
qualified types; and
2) To make things easy the rule forbids some safe conversion like the
one give.

The rule in the standard is designed to prevent modification of a
const like this:

int main(void)
{
const char foo = 'F';
char *p;
const char **cp = (const char **)&p; // force with cast
*cp = &foo;
*p = 'B';

printf("c = %c\n", foo);
return EXIT_SUCCESS;
}

Note that the compiler wants to be able to assume the foo can't change
(and maybe more importantly the programmer wants to assume that!) but
if it allowed the assignment I forced with the cast, the const foo can
be changed, silently.

To keep things simple, the standard says:

6.3.2.3:

[2] For any qualifier q, a pointer to a non-q-qualified type may be
converted to a pointer to the q-qualified version of the type; the
values stored in the original and converted pointers shall compare
equal.

and then:

6.7.3 Type qualifiers

[9] For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type; the order of
type qualifiers within a list of specifiers or qualifiers does not
affect the specified type.

which, I think, allows common (safe) usages, forbids dangerous usages
as above but also rules out certain safe combinations involving more
than one level of indirection.
 
D

d3x0xr

And even at that, if I do typecasst, doesn't that defeat the compiler's
desire to know that a thing is const?




Ben Bacarisse:
Richard Heathfield said:
d3x0xr said:


Consider:

char foo = 'F';
char bar = 'B';
char *baz = &foo;
char **quux = &baz;
char const * const * eric;

eric = quux; /* erroneous, and equivalent to your code */

The compiler ought to be able to know for sure, because eric is a pointer to
a const pointer to char, that *eric will not change. But because you can do
this at any time:

*quux = &bar;

it becomes possible for legal code to subvert the constness of *eric, and
the compiler won't like that even a little bit.

This problem comes from two issues interacting:

1) The standard forbids certain dangerous conversion involving
qualified types; and
2) To make things easy the rule forbids some safe conversion like the
one give.

The rule in the standard is designed to prevent modification of a
const like this:

int main(void)
{
const char foo = 'F';
char *p;
const char **cp = (const char **)&p; // force with cast
*cp = &foo;
*p = 'B';

printf("c = %c\n", foo);
return EXIT_SUCCESS;
}

Note that the compiler wants to be able to assume the foo can't change
(and maybe more importantly the programmer wants to assume that!) but
if it allowed the assignment I forced with the cast, the const foo can
be changed, silently.

To keep things simple, the standard says:

6.3.2.3:

[2] For any qualifier q, a pointer to a non-q-qualified type may be
converted to a pointer to the q-qualified version of the type; the
values stored in the original and converted pointers shall compare
equal.

and then:

6.7.3 Type qualifiers

[9] For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type; the order of
type qualifiers within a list of specifiers or qualifiers does not
affect the specified type.

which, I think, allows common (safe) usages, forbids dangerous usages
as above but also rules out certain safe combinations involving more
than one level of indirection.
 
B

Ben Bacarisse

d3x0xr said:
Ben Bacarisse:
Again, without typecasting. There's no safe way to write code without
getting assaulted by warnrings of undefined conditions.

Why is that? Why MUST I type cast?

I may well have missed your point. I am sorry my answer was of no
help.
I don't in C++.

Different languages have different rules.
I don't in gcc.

If your question is specific to one implementation, then you will get
better help in a newsgroup dedicated to that implementation.

Please don't top-post.
 

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,965
Messages
2,570,148
Members
46,710
Latest member
FredricRen

Latest Threads

Top