Topic: Passing char ** as const char ** should be legal
Author: jr@efi.sintef.no (Jarand Roeynstrand)
Date: 3 Feb 1995 09:29:13 GMT Raw View
In article <3grcvf$epv@news.uni-c.dk>, mojemj@unidhp.uni-c.dk (Mogens Jensen) writes:
[Stuff about Passing char ** as const char ** beeing illegal deleted]
|>
|> I agree that it is a strange restriction, why does it indicate a logic
|> error?, and what is the difference between [char*->const char*] and
|> [char**->const char**]?
|>
|> One could imagine that const meant anti-volatile, so that the compiler
|> was able to make certain presumptions (only load once); and a non-const
|> pointer could possibly violate this assumption - but this can't be the
|> case as [char*->const char*] is allowed (and we have the volatile
|> keyword) ...
|>
Consider this example, that is legal if the conversion [char**->const char**]
is legal:
void f( const char ** p)
{
static const char *message= "Hello world!";
*p = message;
}
main()
{
char *p;
f( &p );
p[0] = 'F'; // Breaks constness of f::message
}
I hope this helps.
(This article is sent once already, but under wrong topic. Sorry)
--
==== Best regards
\\ Jarand Roeynstrand
\\ DIG-hackers department
\====\
.,;,\ \ EFI
,;;;;;;;;,_/ ____ N-7034 Trondheim
| | Norway
| |
\__/
Phone: +47-73 59 72 75 Email: jr@efi.sintef.no
Author: Per Angstrom <eri.edt.edtpang@memo.ericsson.se>
Date: 3 Feb 1995 15:55:30 GMT Raw View
jr@efi.sintef.no (Jarand Roeynstrand) wrote:
> Consider this example, that is legal if the conversion [char**->const char**]
> is legal:
>
> void f( const char ** p)
> {
> static const char *message= "Hello world!";
> *p = message;
> }
>
> main()
> {
> char *p;
> f( &p );
> p[0] = 'F'; // Breaks constness of f::message
> }
>
> I hope this helps.
OK. That helped a lot. I hadn't though of that.
But I won't give up; instead I will restate my claim:
!!! Passing 'char **' as 'const char * const *' should be legal !!!
For proof of this, change the signature of function f to
void f( const char * const * p )
Then you won't be able to do the assignment to *p, and you
will have covered the hole in the type system.
(Until somebody discovers a new hole!)
Author: jason@cygnus.com (Jason Merrill)
Date: Fri, 3 Feb 1995 21:15:42 GMT Raw View
>>>>> Per Angstrom <eri.edt.edtpang@memo.ericsson.se> writes:
> But I won't give up; instead I will restate my claim:
> !!! Passing 'char **' as 'const char * const *' should be legal !!!
And it is.
4.4 Qualification conversions [conv.qual]
1 An rvalue of type pointer to cv1 T can be converted to an rvalue of
type pointer to cv2 T if cv2 T is more cv-qualified than cv1 T. When
a multi-level pointer is composed of data member pointers, or a mix of
object and data member pointers, the rules for adding type qualifiers
are the same as those for object pointers. That is, the ``member''
aspect of the pointers is irrelevant in determining where type quali-
fiers can be added.
2 A conversion can add type qualifiers at levels other than the first in
multi-level pointers, subject to the following rules:3)
Two pointer types T1 and T2 are similar if there exists a type T and
integer N>0 such that:
T1isTcv1,n*...cv1,1*cv1,0
and
T2isTcv2,n*...cv2,1*cv2,0
where each cvi,j is const, volatile, const volatile, or nothing. An
expression of type T1 can be converted to type T2 if and only if the
following conditions are satisfied:
--the pointer types are similar.
_________________________
2) This conversion never applies to member functions because there is
no way to obtain an lvalue for a member function.
3) These rules ensure that const-safety is preserved by the conver-
sion. This conversion never applies to nonstatic member functions be-
cause there is no way to obtain an lvalue for a nonstatic member func-
tion.
--for every j>0, if const is in cv1,j then const is in cv2,j, and
similarly for volatile.
--the cv1,j and cv2,j are different, then const is in every cv2,k
for 0<k<j.
3 An rvalue of type pointer to member of X of type cv1 T can be con-
verted to an rvalue of type pointer to member of X of type cv2 T if
cv2 T is more cv-qualified than cv1 T.
Author: mojemj@unidhp.uni-c.dk (Mogens Jensen)
Date: 4 Feb 1995 03:08:11 GMT Raw View
Per Angstrom (eri.edt.edtpang@memo.ericsson.se) wrote:
: jr@efi.sintef.no (Jarand Roeynstrand) wrote:
: > Consider this example, that is legal if the conversion
: > [char**->const char**] is legal:
: >
: > void f( const char ** p)
: > {
: > static const char *message= "Hello world!";
: > *p = message;
: > }
: >
: > main()
: > {
: > char *p;
: > f( &p );
: > p[0] = 'F'; // Breaks constness of f::message
: > }
: >
: > I hope this helps.
Hey, Great! That explains it. I was very puzzled about this, but of
course you are right!
: OK. That helped a lot. I hadn't though of that.
: But I won't give up; instead I will restate my claim:
: !!! Passing 'char **' as 'const char * const *' should be legal !!!
It *is* !
(Using Borland C++ 4.02 or IBM C++ for OS/2)
Greetings from Jens Jakob Jensen, Denmark - (Using my fathers account)
Author: tob@world.std.com (Tom O Breton)
Date: Sat, 4 Feb 1995 04:30:52 GMT Raw View
Per Angstrom <eri.edt.edtpang@memo.ericsson.se> writes:
[ why doesn't char** assign to const char **? ]
Because then constness could be accidentally removed:
const int ** A;
int ** B;
A = B; //The conversion you want.
assert( *A == *B );
const int * C = 0;
*A = C;
assert( C == *B );
*B = 1;
assert( C == 1 );
Tom
--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower
Author: tob@world.std.com (Tom O Breton)
Date: Sat, 4 Feb 1995 04:30:54 GMT Raw View
Per Angstrom <eri.edt.edtpang@memo.ericsson.se> writes:
[ why doesn't char** assign to const char **? ]
Because then constness could be accidentally removed:
const int ** A;
int ** B;
A = B; //The conversion you want.
assert( *A == *B );
const int * C = 0;
*A = C;
assert( C == *B );
*B = 1;
assert( C == 1 );
Tom
--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sat, 4 Feb 1995 16:59:02 GMT Raw View
Per Angstrom <eri.edt.edtpang@memo.ericsson.se> writes:
>But I won't give up; instead I will restate my claim:
>
>!!! Passing 'char **' as 'const char * const *' should be legal !!!
It is!
Note that allowing this is a relatively recent change, and some
compilers have not yet implemented it.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
all [L] (programming_language(L), L \= "Mercury") => better("Mercury", L) ;-)
Author: pat@tesuji.qc.ca (Patrick Smith)
Date: Sat, 4 Feb 1995 19:25:23 GMT Raw View
Per Angstrom <eri.edt.edtpang@memo.ericsson.se> writes:
>!!! Passing 'char **' as 'const char * const *' should be legal !!!
It is, in the committee's working papers.
Compilers may take a while to catch up.
--
Patrick Smith
pat@tesuji.qc.ca
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 5 Feb 1995 19:45:18 GMT Raw View
In article <3gtjli$lsg@erinews.ericsson.se> Per Angstrom <eri.edt.edtpang@memo.ericsson.se> writes:
>jr@efi.sintef.no (Jarand Roeynstrand) wrote:
>
>> Consider this example, that is legal if the conversion [char**->const char**]
>> is legal:
It isnt. For the reason you give. (It isn't safe)
>
>!!! Passing 'char **' as 'const char * const *' should be legal !!!
It is. Because, as you claim, it is safe.
>
>For proof of this, change the signature of function f to
>
> void f( const char * const * p )
That is a demonstration, not a proof.
>(Until somebody discovers a new hole!)
There's no hole. ISO C does not permit the safe
conversion
char** --> char const* const*
whereas C++ now does. And other similar conversions, see the
Working Paper for a specification. The proof that the
conversions permitted in the WP are safe is due to Pat Smith.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: Per Angstrom <eri.edt.edtpang@memo.ericsson.se>
Date: 2 Feb 1995 14:35:28 GMT Raw View
Consider the following piece of code:
Sample Code
--------------------------------
extern "C" {
char ** old_C_function();
};
void funcA( const char ** )
{
}
void funcB( const char * )
{
}
int main()
{
char ** strings = old_C_function();
funcA( strings ); // line 17: warning
funcB( strings[0] ); // line 18: OK
return 0;
}
Compiler Output
----------------------
When compiling the program I get the following warning from Sun CC 4.0:
>> "atest.cc", line 17: Warning (Anachronism): Formal argument 1 of
>> type const char** in call to funcA(const char**) is being
>> passed char**.
>> "atest.cc", line 17: Note: Type "CC -migration" for more on
>> anachronisms.
>> 1 Warning(s) detected.
Explanation from the Compiler
-------------------------------------
"CC -migration" gives the following explanation:
>> 1.6.13 Formal argument AAAA of type BBBB is being passed CCCC
>> or
>> Formal argument AAAA of type BBBB in call to CCCC is being passed
>> DDDD
>> These warnings indicate that the conversion required to pass the
>> argument is illegal, but that C++ 3.0 did not detect the
>> illegality. Failure to handle const and volatile properly on
>> pointers is a major cause of this problem.
>> You can usually correct it with an explicit cast, but the error is
>> probably the result of a logic error. Passing a value of type
>> char** to an argument of type const char** is illegal in both
>> C++ and ANSI C. This is not an error or oversight in the standard
>> as such assignments open a hole in the type system and violate
>> const safety.
My Opinion
-----------------------------------------------
IMHO, this is too strict. I do agree that implicit conversion _from_
const to non-const should not be done, but I cannot see how implicit
conversion _to_ const could do any harm.
I see three (bad) ways to avoid getting this warning:
1) Of course, I can do an explicit cast, but that I think is an even
bigger hole in the type system, as long as my compiler does not
support the const_cast operator.
2) I can say 'void funcA( char ** );', which will give me a problem when
I want to pass it const char ** arguments.
3) I can modify the signature of old_C_function to return const char **,
but in real life this declaration might be in a header file which I do
not want to tamper with.
My Questions
-----------------------------------------------------------
My questions are: Am I missing something here? Have I not found the right
passage in the holy book? Will somebody please enlighten me?
I also wonder, if the standard is to be consistent, why is line 18 OK?
Post Scriptum
-----------------------------------------
This is not a complaint on Sun CC. Borland C++ 4.0 gives an error
instead of a warning.
Author: mojemj@unidhp.uni-c.dk (Mogens Jensen)
Date: 2 Feb 1995 19:49:03 GMT Raw View
Per Angstrom (eri.edt.edtpang@memo.ericsson.se) wrote:
: Consider the following piece of code:
: Sample Code
: --------------------------------
: extern "C" {
: char ** old_C_function();
: };
: void funcA( const char ** )
: {
: }
: void funcB( const char * )
: {
: }
: int main()
: {
: char ** strings = old_C_function();
: funcA( strings ); // line 17: warning
: funcB( strings[0] ); // line 18: OK
:
: return 0;
: }
: Compiler Output
: ----------------------
: When compiling the program I get the following warning from Sun CC 4.0:
: >> "atest.cc", line 17: Warning (Anachronism): Formal argument 1 of
: >> type const char** in call to funcA(const char**) is being
: >> passed char**.
: >> "atest.cc", line 17: Note: Type "CC -migration" for more on
: >> anachronisms.
: >> 1 Warning(s) detected.
: Explanation from the Compiler
: -------------------------------------
: "CC -migration" gives the following explanation:
: >> 1.6.13 Formal argument AAAA of type BBBB is being passed CCCC
: >> or
: >> Formal argument AAAA of type BBBB in call to CCCC is being passed
: >> DDDD
: >> These warnings indicate that the conversion required to pass the
: >> argument is illegal, but that C++ 3.0 did not detect the
: >> illegality. Failure to handle const and volatile properly on
: >> pointers is a major cause of this problem.
: >> You can usually correct it with an explicit cast, but the error is
: >> probably the result of a logic error. Passing a value of type
: >> char** to an argument of type const char** is illegal in both
: >> C++ and ANSI C. This is not an error or oversight in the standard
: >> as such assignments open a hole in the type system and violate
: >> const safety.
: My Opinion
: -----------------------------------------------
: IMHO, this is too strict. I do agree that implicit conversion _from_
: const to non-const should not be done, but I cannot see how implicit
: conversion _to_ const could do any harm.
: I see three (bad) ways to avoid getting this warning:
: 1) Of course, I can do an explicit cast, but that I think is an even
: bigger hole in the type system, as long as my compiler does not
: support the const_cast operator.
: 2) I can say 'void funcA( char ** );', which will give me a problem when
: I want to pass it const char ** arguments.
: 3) I can modify the signature of old_C_function to return const char **,
: but in real life this declaration might be in a header file which I do
: not want to tamper with.
4) You can use function overloading and make two versions of funcA:
void funcA(char**), funcA(const char**);
I agree that it is a strange restriction, why does it indicate a logic
error?, and what is the difference between [char*->const char*] and
[char**->const char**]?
One could imagine that const meant anti-volatile, so that the compiler
was able to make certain presumptions (only load once); and a non-const
pointer could possibly violate this assumption - but this can't be the
case as [char*->const char*] is allowed (and we have the volatile
keyword) ...
I am puzzled...
: Post Scriptum
: -----------------------------------------
: This is not a complaint on Sun CC. Borland C++ 4.0 gives an error
: instead of a warning.
Greetings from Jens Jakob Jensen, Denmark - (Using my fathers account)