Topic: strtol const-ness problem
Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Mon, 21 Aug 2006 05:07:11 CST Raw View
I wrote:
> 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!
>
Sorry, in fact it would only break code which passes a "const char*" as
first argument to strtol, which is still a huge base 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 ]
Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Mon, 21 Aug 2006 05:06:49 CST Raw View
kanze wrote:
[snip]
> 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 ]
Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Fri, 18 Aug 2006 16:41:41 CST Raw View
kanze wrote:
> 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 ]
Author: "dstevel" <google@lakepage.com>
Date: Mon, 21 Aug 2006 04:40:56 CST Raw View
Thank you all for your responses. I wanted to reply to Greg who thought
it would be unusual to scan a const string. That might be true if it
was a string declared in the code and known at compile time. But,
consider an std::string from some source. (Or a stream for that
matter). Then, using myString.c_str() to obtain a const char* would be
OK if you want to use strtol. If we allow something to mess with the
internal memory of the std::string, it could be "bad". So I wanted to
enforce const-correctness in my function that uses strtol without
casting it away or making non-const copies/temporaries. It looks
const_cast will have to do for the call to strtol and that will not
leave me with any usable non-const pointers into the original string. I
just need to trust that strtol is playing nice.
Thanks again,
~Dan
Greg Herlihy wrote:
> 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 ]
---
[ 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 ]
Author: "Kristof Zelechovski" <giecrilj@stegny.2a.pl>
Date: Wed, 16 Aug 2006 11:28:50 CST Raw View
Uzytkownik "Manfred von Willich" <manfred@techniroot.co.za> napisal w
wiadomosci news:1155587670.517846.8770@h48g2000cwc.googlegroups.com...
>
> 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 ]
Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 17 Aug 2006 12:09:17 CST Raw View
Manfred von Willich wrote:
> 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;
> > > }
[...]
> > 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.
> 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 ]
Author: "dstevel" <google@lakepage.com>
Date: Sat, 12 Aug 2006 15:38:54 CST Raw View
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 ]
Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Sun, 13 Aug 2006 11:28:39 CST Raw View
dstevel wrote:
> 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.
> 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 ]
Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Mon, 14 Aug 2006 15:53:35 CST Raw View
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.
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 ]
Author: hozwirk.SPAM@arcor.de ("Heinz Ozwirk")
Date: Mon, 14 Aug 2006 23:49:08 GMT Raw View
"Manfred von Willich" <manfred@techniroot.co.za> schrieb im Newsbeitrag
news:1155587670.517846.8770@h48g2000cwc.googlegroups.com...
> 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 ]