C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

strtol const-ness problem

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
dstevel
Guest





PostPosted: Sat Aug 12, 2006 9:38 pm    Post subject: strtol const-ness problem Reply with quote



Note: This was originally posted in comp.lang.c++ and it was
recommended that I post it to std so here it is.
=======================

The signature for strtol is:

strtol( const char*, char**, int)

So.. if we start with a passed "const char*" (pointer to const char),
then we can't create a non-const char pointer pointer to that const
char pointer as in:

void func( const char* a )
{
// ERROR: invalid conversion from `const char**' to `char**'
char** pa = &a;
int i = strtol( a, pa, 10 );

}

And here is another way of saying the same thing without temporary
variables.

void func( const char* a )
{
// ERROR: invalid conversion from `const char**' to `char**'
// ERROR: initializing argument 2 of `long int strtol...
int i = strtol( a, &a, 10 );

}

But you CAN do:

void func( const char* a )
{
int i = strtol( a, (char**)&a, 10 ); // OK

}

AND you can also do this:

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 ); // OK
a = tmp;

}

This indirectly allows us to modify the original const char* a through
the new pointer tmp since tmp will point into the character array a. It
doesn't involve a hard cast, but it seems just as dangerous or even
more so because it's not obvious what just happened. The calling
function could see a change in the string pointed to by a, even though
it's passed as pointer to const.

Can someone help me figure out why this is OK?

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Greg Herlihy
Guest





PostPosted: Sun Aug 13, 2006 5:28 pm    Post subject: Re: strtol const-ness problem Reply with quote



dstevel wrote:
Quote:
Note: This was originally posted in comp.lang.c++ and it was
recommended that I post it to std so here it is.
=======================

The signature for strtol is:

strtol( const char*, char**, int)

So.. if we start with a passed "const char*" (pointer to const char),
then we can't create a non-const char pointer pointer to that const
char pointer as in:

void func( const char* a )
{
// ERROR: invalid conversion from `const char**' to `char**'
char** pa = &a;
int i = strtol( a, pa, 10 );

}

And here is another way of saying the same thing without temporary
variables.

void func( const char* a )
{
// ERROR: invalid conversion from `const char**' to `char**'
// ERROR: initializing argument 2 of `long int strtol...
int i = strtol( a, &a, 10 );

}

But you CAN do:

void func( const char* a )
{
int i = strtol( a, (char**)&a, 10 ); // OK

}

AND you can also do this:

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 ); // OK
a = tmp;

}

This indirectly allows us to modify the original const char* a through
the new pointer tmp since tmp will point into the character array a. It
doesn't involve a hard cast, but it seems just as dangerous or even
more so because it's not obvious what just happened. The calling
function could see a change in the string pointed to by a, even though
it's passed as pointer to const.

The called function can still use a const_cast to change the value
referenced by the const pointer. So about the only variables that a
program can treat as unmodifiable are those defined as const.

Quote:
Can someone help me figure out why this is OK?

First it would be rather unusual (not to mention inefficient) for a
program to spend its cycles scanning text for numbers - when the
contents of text being scanned (and by extension, the number values
contained therein) are both constant and were known at compile time.
Therefore, in the vast majority of cases, it is likely that strtol will
be called to process non-const character values.

Second, most C++ programmers are accustomed to be able to pass a
pointer to non-const (such as char *) whenever a function declares a
pointer to const parameter. So, by extension, it is likely that C++
programmers would expect to be able to pass a pointer to a pointer to
non const whenever a pointer to a pointer to const parameter is
declared (in other words to pass char** for a a const char**
parameter).

As it turns out, a char** pointer cannot be used in place of const
char** parameter:

// assume:
long strtol(const char *nptr, const char **endptr, int base);

...
char *s = "15";

long n;
n = strtol(s, &s, 10);// ERROR:
// invalid conversion: char** to const char**

So were strtol's second parameter declared a const char** pointer, then
C++ programmers would be quite likely to encounter this
counterintuitive conversion error. Furthermore, give the first point
above (that the string being scanned will - in all likelihood - be
non-const) encountering this error becomes ever more likely - at least
when compared against its counterpart - the error that is seen today:
(whenever a program tries to pass a const char** pointer for strtol's
char**, second parameter.)

Finally, since a cast will be necessary either in one case or the other
- it seems that a decision favoring the less unusual cast in the less
likely scenario is, on the whole, nothing other than a decision to
annoy fewer C++ programmers, the fewer number of times.

Greg

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Manfred von Willich
Guest





PostPosted: Mon Aug 14, 2006 9:53 pm    Post subject: Re: strtol const-ness problem Reply with quote



Greg Herlihy wrote:
Quote:
dstevel wrote:
The signature for strtol is:

strtol( const char*, char**, int)

[snip]

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 ); // OK
a = tmp;
}

This indirectly allows us to modify the original const char* a through
the new pointer tmp since tmp will point into the character array a. It
doesn't involve a hard cast, but it seems just as dangerous or even
more so because it's not obvious what just happened. The calling
function could see a change in the string pointed to by a, even though
it's passed as pointer to const.

The called function can still use a const_cast to change the value
referenced by the const pointer. So about the only variables that a
program can treat as unmodifiable are those defined as const.

Can someone help me figure out why this is OK?

First it would be rather unusual (not to mention inefficient) for a
program to spend its cycles scanning text for numbers - when the
contents of text being scanned (and by extension, the number values
contained therein) are both constant and were known at compile time.
Therefore, in the vast majority of cases, it is likely that strtol will
be called to process non-const character values.

This is not the only context - it is perfectly reasonable (and *not*
unusual) for a function to have char const * formal parameter and a
const * actual parameter, meaning that the function guarantees not to
modify the (potentially non-const) string, and for this function then
to pass the pointer to strtol. IMHO the signature is not const-correct
- see below.

Quote:
Second, most C++ programmers are accustomed to be able to pass a
pointer to non-const (such as char *) whenever a function declares a
pointer to const parameter. So, by extension, it is likely that C++
programmers would expect to be able to pass a pointer to a pointer to
non const whenever a pointer to a pointer to const parameter is
declared (in other words to pass char** for a a const char**
parameter).

The more often C/C++ programmers get disabused of this
misconception/expectation, the faster they'll learn correct usage. No
point in supporting incorrect usage simply because the correct usage is
counterintuitive to the less experienced.

Quote:
[snip]

Finally, since a cast will be necessary either in one case or the other
- it seems that a decision favoring the less unusual cast in the less
likely scenario is, on the whole, nothing other than a decision to
annoy fewer C++ programmers, the fewer number of times.

Greg

On the contrary, the existing signature can be used without casts for
all uses, though safety is sacrificed:

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 );
const char* b = tmp; // any other use of tmp is unsafe, b is
safe (no cast).
}

A const-correct library would have had the signature:

long strtol (const char *nptr, const char **endptr, int base);

However, given that a function may wish to scan and then modify data
from the point scanned to (I expect this use to be far less common),
the following additional signature would have been appropriate:

long strtol (char *nptr, char **endptr, int base);

In C++, two signatures would have been fine. Given that the signature
is in <stdlib.h>, the linkage is extern"C", an overloaded signature is
precluded. I surmise that the provided signature is a compromise,
supporting both uses, but relying on the programmer not to do
"something silly" with the returned pointer.

A bit of a diversion:

Given the const-incorrectness of the signature, I would have advocated
the following single const-correct signature for supporting all
const-correct cases (though it is presumably too late to propose this):

long strtol_new (const char *nptr, int *scannedchars, int base);

With this, the constness is exact (i.e. the compiler will permit all
safe and no unsafe combinations of uncommenting the "const"):

char /*const*/ * a = "1234abcd";
int i;
long value = strtol_new(a,&i,10);
char /*const*/ * p = a+i; // the original endptr parameter

Manfred

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Heinz Ozwirk
Guest





PostPosted: Tue Aug 15, 2006 4:49 am    Post subject: Re: strtol const-ness problem Reply with quote

"Manfred von Willich" <manfred (AT) techniroot (DOT) co.za> schrieb im Newsbeitrag
news:1155587670.517846.8770 (AT) h48g2000cwc (DOT) googlegroups.com...
Quote:
A const-correct library would have had the signature:

long strtol (const char *nptr, const char **endptr, int base);

However, given that a function may wish to scan and then modify data
from the point scanned to (I expect this use to be far less common),
the following additional signature would have been appropriate:

long strtol (char *nptr, char **endptr, int base);

In C++, two signatures would have been fine. Given that the signature
is in <stdlib.h>, the linkage is extern"C", an overloaded signature is
precluded. I surmise that the provided signature is a compromise,
supporting both uses, but relying on the programmer not to do
"something silly" with the returned pointer.

C++ uses its own header files, cstdlib in this case. So there would be no
problem to provide two overloads for strtol. Other functions in cstdlib,
like strchr, actually do provide two overloads for pointers to const and
non-const character arrays. So, why not strtol?

Heinz


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Kristof Zelechovski
Guest





PostPosted: Wed Aug 16, 2006 5:28 pm    Post subject: Re: strtol const-ness problem Reply with quote

Uzytkownik "Manfred von Willich" <manfred (AT) techniroot (DOT) co.za> napisal w
wiadomosci news:1155587670.517846.8770 (AT) h48g2000cwc (DOT) googlegroups.com...
Quote:

Greg Herlihy wrote:
dstevel wrote:
The signature for strtol is:

strtol( const char*, char**, int)

[snip]

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 ); // OK
a = tmp;
}

This indirectly allows us to modify the original const char* a through
the new pointer tmp since tmp will point into the character array a. It
doesn't involve a hard cast, but it seems just as dangerous or even
more so because it's not obvious what just happened. The calling
function could see a change in the string pointed to by a, even though
it's passed as pointer to const.

The called function can still use a const_cast to change the value
referenced by the const pointer. So about the only variables that a
program can treat as unmodifiable are those defined as const.

Can someone help me figure out why this is OK?

First it would be rather unusual (not to mention inefficient) for a
program to spend its cycles scanning text for numbers - when the
contents of text being scanned (and by extension, the number values
contained therein) are both constant and were known at compile time.
Therefore, in the vast majority of cases, it is likely that strtol will
be called to process non-const character values.

This is not the only context - it is perfectly reasonable (and *not*
unusual) for a function to have char const * formal parameter and a
const * actual parameter, meaning that the function guarantees not to
modify the (potentially non-const) string, and for this function then
to pass the pointer to strtol. IMHO the signature is not const-correct
- see below.

Second, most C++ programmers are accustomed to be able to pass a
pointer to non-const (such as char *) whenever a function declares a
pointer to const parameter. So, by extension, it is likely that C++
programmers would expect to be able to pass a pointer to a pointer to
non const whenever a pointer to a pointer to const parameter is
declared (in other words to pass char** for a a const char**
parameter).

The more often C/C++ programmers get disabused of this
misconception/expectation, the faster they'll learn correct usage. No
point in supporting incorrect usage simply because the correct usage is
counterintuitive to the less experienced.

[snip]

Finally, since a cast will be necessary either in one case or the other
- it seems that a decision favoring the less unusual cast in the less
likely scenario is, on the whole, nothing other than a decision to
annoy fewer C++ programmers, the fewer number of times.

Greg

On the contrary, the existing signature can be used without casts for
all uses, though safety is sacrificed:

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 );
const char* b = tmp; // any other use of tmp is unsafe, b is
safe (no cast).
}

A const-correct library would have had the signature:

long strtol (const char *nptr, const char **endptr, int base);

However, given that a function may wish to scan and then modify data
from the point scanned to (I expect this use to be far less common),
the following additional signature would have been appropriate:

long strtol (char *nptr, char **endptr, int base);

In C++, two signatures would have been fine. Given that the signature
is in <stdlib.h>, the linkage is extern"C", an overloaded signature is
precluded. I surmise that the provided signature is a compromise,
supporting both uses, but relying on the programmer not to do
"something silly" with the returned pointer.


Suppose you have extern "C" strtol(char const [], char const **, int). How
do you make a non-const overload?

A: First, we should use a reference instead of a pointer.
static inline long strtol(char const buf[], char const *&end, int base) {
return strtol(buf, &end, base); }
Next, observe that we can do pointer arithmetic on pointers belonging to the
same buffer:
static inline long strtol(char buf[], char *&end, int base) {
auto char const *gotyou; auto long result(strtol(buf, gotyou, base)); end =
gotyou - buf + buf; return result; }
Ready.
Chris



---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
kanze
Guest





PostPosted: Thu Aug 17, 2006 6:09 pm    Post subject: Re: strtol const-ness problem Reply with quote

Manfred von Willich wrote:
Quote:
Greg Herlihy wrote:
dstevel wrote:
The signature for strtol is:

strtol( const char*, char**, int)

[snip]

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 ); // OK
a = tmp;
}

[...]
Quote:
First it would be rather unusual (not to mention
inefficient) for a program to spend its cycles scanning text
for numbers - when the contents of text being scanned (and
by extension, the number values contained therein) are both
constant and were known at compile time. Therefore, in the
vast majority of cases, it is likely that strtol will be
called to process non-const character values.

This is not the only context - it is perfectly reasonable (and
*not* unusual) for a function to have char const * formal
parameter and a const * actual parameter, meaning that the
function guarantees not to modify the (potentially non-const)
string, and for this function then to pass the pointer to
strtol. IMHO the signature is not const-correct - see below.
[snip]

Finally, since a cast will be necessary either in one case
or the other - it seems that a decision favoring the less
unusual cast in the less likely scenario is, on the whole,
nothing other than a decision to annoy fewer C++
programmers, the fewer number of times.

On the contrary, the existing signature can be used without
casts for all uses, though safety is sacrificed:

void func( const char* a )
{
char* tmp;
int i = strtol( a, &tmp, 10 );
const char* b = tmp; // any other use of tmp is unsafe, b is
safe (no cast).
}

A const-correct library would have had the signature:

long strtol (const char *nptr, const char **endptr, int base);

However, given that a function may wish to scan and then
modify data from the point scanned to (I expect this use to be
far less common), the following additional signature would
have been appropriate:

long strtol (char *nptr, char **endptr, int base);

In C++, two signatures would have been fine. Given that the
signature is in <stdlib.h>, the linkage is extern"C", an
overloaded signature is precluded.

Why? And where does it say that the linkage is extern "C"?

In most such cases, where the C function takes a char const*,
and returns a char*, the C++ standard does require the overload.
And since neither of the overloaded functions is compatible with
the corresponding C function, I would expect that the *NOT* be
extern "C". In fact, because it would interfere with overload
resolution, I don't think that the compatible C signature can
even be present.

The reason why this is not the case for stdtol is doubtlessly
because the committee overlooked it. Such things do happen.

Quote:
I surmise that the provided signature is a compromise,
supporting both uses, but relying on the programmer not to do
"something silly" with the returned pointer.

The provided signature is that of C; your evaluation for C is
correct, because there is no possibility of overloading. In
most cases, where C did such things, C++ has provided the
overloads. Including in the <xxx.h> headers.

As I said, I think that this is just a case of oversight, and
that a defect report, made quickly enough, would see it
corrected in the next version of the standard.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
SuperKoko
Guest





PostPosted: Fri Aug 18, 2006 10:41 pm    Post subject: Re: strtol const-ness problem Reply with quote

kanze wrote:

Quote:
The provided signature is that of C; your evaluation for C is
correct, because there is no possibility of overloading. In
most cases, where C did such things, C++ has provided the
overloads. Including in the <xxx.h> headers.

As I said, I think that this is just a case of oversight, and
that a defect report, made quickly enough, would see it
corrected in the next version of the standard.

I agree.

As there are two strstr overloads:


const char* strstr(const char* s1, const char* s2);
char* strstr( char* s1, const char* s2);

There should be two strtol overloads:

long int strtol (char *nptr, char **endptr, int base);
long int strtol (const char *nptr, const char **endptr, int base);

However, since a const char** can't be converted implicitly to a
char**, it means that actual code looks like:
{
char* endp;
long value=strtol(nptr, &endp, 0);
}

And, since char** can't be converted to const char**, it means that ALL
the current code base (did I missed something) which uses strtol would
break!

:(

I admit that the actual situation is deffective. But I fear that it
can't be changed without breaking much code.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Manfred von Willich
Guest





PostPosted: Mon Aug 21, 2006 11:06 am    Post subject: Re: strtol const-ness problem Reply with quote

kanze wrote:
[snip]
Quote:
The provided signature is that of C; your evaluation for C is
correct, because there is no possibility of overloading. In
most cases, where C did such things, C++ has provided the
overloads. Including in the <xxx.h> headers.

As I said, I think that this is just a case of oversight, and
that a defect report, made quickly enough, would see it
corrected in the next version of the standard.

I'm glad this is the case (also suggested by Heinz in his responses).
I'm glad to have stimulated discussion on dstevel's original query, but
not being a committee member, I wouldn't know much about either writing
up or submitting a DR, let alone what the actual state of the standard
is.

Can anyone with flying hours take this up?

Manfred

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.