Caution is necessary here. The behaviours of islower and toupper
are undefined if they are passed a value that is neither EOF nor
representable as an unsigned char. It is good practice, therefore,
to cast *string to unsigned char. (No need to cast it back to
int afterwards, since the normal promotion rules handle that.)

which allows for the fact that some chars do not have an upper or
lower case to be flipped.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

There is no need to cast the argument to toupper() to unsigned char.
We assume that st points to a valid string. All characters of such a
string are within the range 0..CHAR_MAX by definition. CHAR_MAX is
within UCHAR_MAX by definition.

If st points to something not a valid string, and toupper() is
presented with something out of range, (-20 for example) it may
SEGFAULT. And why not? It might tell you where your error is.

--
Joe Wright mailto:
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---

And someone whose name is "Pól" has a name that is an "invalid
string"?
>All characters of such a string are within the range 0..CHAR_MAX
>by definition. CHAR_MAX is within UCHAR_MAX by definition.

If you use ISO-Latin-1, and have signed characters -- and both of
these are quite commonly true today -- you *will* have characters
whose value is outside the [0..CHAR_MAX] range. For instance, the
o-with-accent-acute above is 0xf3 or -13.
>If st points to something not a valid string, and toupper() is
>presented with something out of range, (-20 for example) it may
>SEGFAULT. And why not? It might tell you where your error is.

Or it may change the guy's name from Pól (the Celtic form of
the name "Paul") to PzL, which might just annoy him. If he happens
to have a large sword, this could be a bad strategy.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.

Joe Wright wrote:
> [...]
>> Lew Pitcher wrote:
>>
>> Caution is necessary here. The behaviours of islower and toupper
>> are undefined if they are passed a value that is neither EOF nor
>> representable as an unsigned char. It is good practice, therefore,
>> to cast *string to unsigned char. (No need to cast it back to
>> int afterwards, since the normal promotion rules handle that.)
>> [...]
>
> There is no need to cast the argument to toupper() to unsigned char.

Didn't we just do this a week or so ago? Perhaps it's
a candidate for the FAQ; it seems at any rate to be FA.
> We
> assume that st points to a valid string. All characters of such a string
> are within the range 0..CHAR_MAX by definition.

No, they are in the range CHAR_MIN through CHAR_MAX.
Since `char' may be a signed type (it's the implementation's
choice), CHAR_MIN can be negative. It's true that all the
characters mandated by the Standard are required to be non-
negative, but the Standard allows the implementation to define
additional characters, too -- and some of these may have
negative codes.
> CHAR_MAX is within
> UCHAR_MAX by definition.

True, but CHAR_MIN can be negative, hence outside the
range of `unsigned char'.
> If st points to something not a valid string, and toupper() is presented
> with something out of range, (-20 for example) it may SEGFAULT. And why
> not? It might tell you where your error is.

Except that the "error" isn't the presence of a -20 in
the string (in one widely-used scheme, -20 is "Latin small
i with grave accent"). The real error is the failure to
use the cast that Lew recommends.

Completely unnecessary conditional test.
> s++;
> }
> } /* flipcase, untested */
>
> which allows for the fact that some chars do not have an upper or
> lower case to be flipped.

(sigh)

7.4.2.1 The tolower function
Synopsis
1 #include <ctype.h>
int tolower(int c);
Description
2 The tolower function converts an uppercase letter to a corresponding
lowercase letter.
Returns
3 If the argument is a character for which isupper is true and there
are one or more corresponding characters, as specified by the current
locale, for which islower is true, the tolower function returns one of
the corresponding characters (always the same one for any given
locale); otherwise, the argument is returned unchanged.

7.4.2.2 The toupper function
Synopsis
1 #include <ctype.h>
int toupper(int c);
Description
2 The toupper function converts a lowercase letter to a corresponding
uppercase letter.
Returns
3 If the argument is a character for which islower is true and there
are one or more corresponding characters, as specified by the current
locale, for which isupper is true, the toupper function returns one of
the corresponding characters (always the same one for any given
locale); otherwise, the argument is returned unchanged.

So the tests are totally unnecessary.

But suppose:

char test [] = "Hello" "\xf0" "World";

....then your function causes undefined behavior on an implementation
with CHAR_BIT 8 and signed char, because you will pass an invalid
value to tolower() or toupper().

Eric Sosman wrote:
> Joe Wright wrote:
>
>> [...]
>>
>>> Lew Pitcher wrote:
>>>
>>> Caution is necessary here. The behaviours of islower and toupper
>>> are undefined if they are passed a value that is neither EOF nor
>>> representable as an unsigned char. It is good practice, therefore,
>>> to cast *string to unsigned char. (No need to cast it back to
>>> int afterwards, since the normal promotion rules handle that.)
>>> [...]
>>
>>
>> There is no need to cast the argument to toupper() to unsigned char.
>
>
> Didn't we just do this a week or so ago? Perhaps it's
> a candidate for the FAQ; it seems at any rate to be FA.
>
Yes we did. It remains to be seen whether I can learn enough from
one beating to avoid the next one.
>> We assume that st points to a valid string. All characters of such a
>> string are within the range 0..CHAR_MAX by definition.
>
>
> No, they are in the range CHAR_MIN through CHAR_MAX.
> Since `char' may be a signed type (it's the implementation's
> choice), CHAR_MIN can be negative. It's true that all the
> characters mandated by the Standard are required to be non-
> negative, but the Standard allows the implementation to define
> additional characters, too -- and some of these may have
> negative codes.
>
Yes, and I truly missed that until just now. Thank you.
>> CHAR_MAX is within UCHAR_MAX by definition.
>
>
> True, but CHAR_MIN can be negative, hence outside the
> range of `unsigned char'.
>
Yes, but I never mentioned CHAR_MIN.
>> If st points to something not a valid string, and toupper() is
>> presented with something out of range, (-20 for example) it may
>> SEGFAULT. And why not? It might tell you where your error is.
>
>
> Except that the "error" isn't the presence of a -20 in
> the string (in one widely-used scheme, -20 is "Latin small
> i with grave accent"). The real error is the failure to
> use the cast that Lew recommends.
>
It didn't occur to me that the value of é (130) was negative as a
signed char (10000010) and when promoted to int would be -126.

I apologize to you and the group for my noise. I'll get it right
next time, I promise. :=)

--
Joe Wright mailto:
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---

But checking islower() or isupper() does not protect from this,
because islower() and isupper() have the same fundamental requirement..
>From ISO/IEC 9899:1999 (E) :
"The header <ctype.h> declares several functions useful for classifying
and mapping characters.166) In all cases the argument is an int, the
value of which shall be representable as an unsigned char or shall
equal the value of the macro EOF. If the argument has any other value,
the behavior is undefined."
isupper(0xf0) is just as undefined as toupper(0xf0) is.

Chris Torek wrote:
> In article <>
> Joe Wright <> wrote:
>
>>The islower() call is unnecessary.
>
>
> Indeed.
>
>
>>char *upper(char *st) {
>> char *s = st;
>> while ((*s = toupper(*s))) ++s;
>> return st;
>>}
>>
>>There is no need to cast the argument to toupper() to unsigned char.
>>We assume that st points to a valid string.
>
>
> And someone whose name is "Pól" has a name that is an "invalid
> string"?
>
>
>>All characters of such a string are within the range 0..CHAR_MAX
>>by definition. CHAR_MAX is within UCHAR_MAX by definition.
>
>
> If you use ISO-Latin-1, and have signed characters -- and both of
> these are quite commonly true today -- you *will* have characters
> whose value is outside the [0..CHAR_MAX] range. For instance, the
> o-with-accent-acute above is 0xf3 or -13.
>
It looks something like ó (162) at my house. 10100010 is -94 but
your point is taken. I didn't consider negative char as valid.
>
>>If st points to something not a valid string, and toupper() is
>>presented with something out of range, (-20 for example) it may
>>SEGFAULT. And why not? It might tell you where your error is.
>
>
> Or it may change the guy's name from Pól (the Celtic form of
> the name "Paul") to PzL, which might just annoy him. If he happens
> to have a large sword, this could be a bad strategy.

I'll try to stay away from that sword. I'm sorry to have muddied the
water. I'll get it wright next time, I promise.

--
Joe Wright mailto:
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---

Eric Sosman wrote:
>
> Except that the "error" isn't the presence of a -20 in
> the string (in one widely-used scheme, -20 is "Latin small
> i with grave accent"). The real error is the failure to
> use the cast that Lew recommends.

If you examine my function you will find that isupper/lower and
toupper/lower are always operating on an unsigned char. The tests
are necessary, to decide whether to upshift or downshift, although
the second can probably be eliminated. However that would leave
the action somewhat unclear, as it is no longer obvious that some
characters are never transformed.

While busily charging off in all directions you failed to even read
the verbiage I attached, and missed the fact that the conditional
expressions lacked a closing parenthesis, and thus were syntax
errors.

The function will convert test[] to "hELLO" "\xf0" "wORLD".

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

infobahn wrote:
> Eric Sosman wrote:
>
>> Except that the "error" isn't the presence of a -20 in
>>the string (in one widely-used scheme, -20 is "Latin small
>>i with grave accent"). The real error is the failure to
>>use the cast that Lew recommends.
>
>
> Ahem. That /Lew/ recommends? Am I invisible all of a sudden?

My apologies; I mistook >>> for >> (or maybe the
other way around) in the attrisnipbutions.

On Sun, 16 Jan 2005 05:16:37 GMT, CBFalconer <>
wrote in comp.lang.c:
> > CBFalconer <>
>
> If you examine my function you will find that isupper/lower and
> toupper/lower are always operating on an unsigned char. The tests
> are necessary, to decide whether to upshift or downshift, although
> the second can probably be eliminated. However that would leave
> the action somewhat unclear, as it is no longer obvious that some
> characters are never transformed.
>
> While busily charging off in all directions you failed to even read
> the verbiage I attached, and missed the fact that the conditional
> expressions lacked a closing parenthesis, and thus were syntax
> errors.
>
> The function will convert test[] to "hELLO" "\xf0" "wORLD".

Share This Page

Welcome to The Coding Forums!

Welcome to the Coding Forums, the place to chat about anything related to programming and coding languages.

Please join our friendly community by clicking the button below - it only takes a few seconds and is totally free. You'll be able to ask questions about coding or chat with the community and help others.
Sign up now!