By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,778 Members | 1,890 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,778 IT Pros & Developers. It's quick & easy.

Is this (tiny) function portable?

P: n/a
Hello,

I am missing certain functionality of std::string, so I am currently
writing some helper functions which operate on strings. On of them is as
follows (it's actually two functions):

inline char to_lower ( char c )
{
if( c>=65 && c<=90 ) // A-Z
return c += 32;
return c;
}

inline void str_to_lower ( std::string& source )
{
std::transform( source.begin(), source.end(), source.begin(),
to_lower );
}

My question concerns the function to_lower:
Is this portable? I looked at an ASCII table, and recognized that I can
convert uppercase letters to lowercase by adding 32. However, I have no
idea if this will work for other character tables.

--
Regards,
Matthias
Jul 23 '05 #1
Share this Question
Share on Google+
20 Replies


P: n/a
* Matthias:
Hello,

I am missing certain functionality of std::string, so I am currently
writing some helper functions which operate on strings. On of them is as
follows (it's actually two functions):

inline char to_lower ( char c )
{
if( c>=65 && c<=90 ) // A-Z
return c += 32;
return c;
}

inline void str_to_lower ( std::string& source )
{
std::transform( source.begin(), source.end(), source.begin(),
to_lower );
}

My question concerns the function to_lower:
Is this portable? I looked at an ASCII table, and recognized that I can
convert uppercase letters to lowercase by adding 32. However, I have no
idea if this will work for other character tables.


It's not portable.

Check out the 'tolower' function.

Beware of argument and result types.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #2

P: n/a
Alf P. Steinbach wrote:

Check out the 'tolower' function.
Ah, could have guessed that there is something like it... :)
I have a question though. I included <cctype> instead of <ctype.h>.
Now, I thought all those forwarding headers wrap the C-functions in the
namespace std? However, when I call std::tolower, I get an error that
this function doesn't exist. When calling without the namespace-prefix
it works just fine. Why ist that?

Beware of argument and result types.

What do you mean?

--
Regards,
Matthias
Jul 23 '05 #3

P: n/a
Matthias wrote:
Hello,

I am missing certain functionality of std::string, so I am currently
writing some helper functions which operate on strings. On of them is as
follows (it's actually two functions):

inline char to_lower ( char c )
{
if( c>=65 && c<=90 ) // A-Z
return c += 32;
return c;
}

inline void str_to_lower ( std::string& source )
{
std::transform( source.begin(), source.end(), source.begin(),
to_lower );
}

My question concerns the function to_lower:
Is this portable?
No.
I looked at an ASCII table, and recognized that I can convert uppercase
letters to lowercase by adding 32. However, I have no idea if this will
work for other character tables.


It won't. As someone else mentioned, just use tolower().

Jul 23 '05 #4

P: n/a
Matthias wrote:
Alf P. Steinbach wrote:

Check out the 'tolower' function.

Ah, could have guessed that there is something like it... :)
I have a question though. I included <cctype> instead of <ctype.h>.
Now, I thought all those forwarding headers wrap the C-functions in the
namespace std? However, when I call std::tolower, I get an error that
this function doesn't exist. When calling without the namespace-prefix
it works just fine. Why ist that?

tolower isn't a function, it's a macro.
Macro's don't have any clue of scope (hence they are ignorant of namespaces).
Jul 23 '05 #5

P: n/a
Ron Natalie wrote:
Matthias wrote:
Alf P. Steinbach wrote:

Check out the 'tolower' function.


Ah, could have guessed that there is something like it... :)
I have a question though. I included <cctype> instead of <ctype.h>.
Now, I thought all those forwarding headers wrap the C-functions in
the namespace std? However, when I call std::tolower, I get an error
that this function doesn't exist. When calling without the
namespace-prefix it works just fine. Why ist that?


tolower isn't a function, it's a macro.
Macro's don't have any clue of scope (hence they are ignorant of
namespaces).


I have read the header file, and as far as I can tell, <cctype> #undef's
all macros and uses inline functions instead, because it is the cleaner
approach.

--
Regards,
Matthias
Jul 23 '05 #6

P: n/a
* Ron Natalie:
Matthias wrote:
Alf P. Steinbach wrote:

Check out the 'tolower' function.

Ah, could have guessed that there is something like it... :)
I have a question though. I included <cctype> instead of <ctype.h>.
Now, I thought all those forwarding headers wrap the C-functions in the
namespace std? However, when I call std::tolower, I get an error that
this function doesn't exist. When calling without the namespace-prefix
it works just fine. Why ist that?


Possibly a non-conforming C++ implementation, possibly that you
somewhere have or #include a macro that redefines 'tolower'.

tolower isn't a function, it's a macro.
Macro's don't have any clue of scope (hence they are ignorant of namespaces).


In the standard it's documented as a function, not as a macro.

So if it's a macro then that's a non-conforming C++ implementation.

Btw., the thing about types is that 'tolower' takes an 'int' argument,
which should be the character value as 'unsigned char'. If the default
'char' type is signed, then certain characters may have negative values
as 'char', and when passed directly to 'tolower' yield values not
representable as 'unsigned char'. So cast to 'unsigned char' first.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #7

P: n/a
Alf P. Steinbach wrote:
Possibly a non-conforming C++ implementation, possibly that you
somewhere have or #include a macro that redefines 'tolower'.
It's the GNU implementation of C++.
Btw., the thing about types is that 'tolower' takes an 'int' argument,
which should be the character value as 'unsigned char'.
If the function can only handle unsigned chars, why does it take an int? ^^

If the default 'char' type is signed, then certain characters may have negative values
as 'char', and when passed directly to 'tolower' yield values not
representable as 'unsigned char'. So cast to 'unsigned char' first.


Alright.
--
Regards,
Matthias
Jul 23 '05 #8

P: n/a
Matthias wrote:
Alf P. Steinbach wrote:
Possibly a non-conforming C++ implementation, possibly that you
somewhere have or #include a macro that redefines 'tolower'.


It's the GNU implementation of C++.
> Btw., the thing about types is that 'tolower' takes an 'int'

argument,
which should be the character value as 'unsigned char'.


If the function can only handle unsigned chars, why does it take an
int? ^^


It is an ancient rule in C (and so it came to C++ in the bag) that char is
always promoted to int. In some cases (at least one case I know) it has a
very important role. Some functions returning (normally) characters should
also be able to return EOF (the end of file constant), which will be a "real
int", not a promoted char.

--
Attila aka WW
Jul 23 '05 #9

P: n/a
Attila Feher wrote:
Matthias wrote:
Alf P. Steinbach wrote:

Possibly a non-conforming C++ implementation, possibly that you
somewhere have or #include a macro that redefines 'tolower'.


It's the GNU implementation of C++.
> Btw., the thing about types is that 'tolower' takes an 'int'

argument,
which should be the character value as 'unsigned char'.


If the function can only handle unsigned chars, why does it take an
int? ^^

It is an ancient rule in C (and so it came to C++ in the bag) that char is
always promoted to int. In some cases (at least one case I know) it has a
very important role. Some functions returning (normally) characters should
also be able to return EOF (the end of file constant), which will be a "real
int", not a promoted char.

--
Attila aka WW


I just recognized that I can't cast because I'm using std::transform, so
I have no influence on the arguments passed. But since they come from an
std::string they are most probably valid characters right? =)

--
Regards,
Matthias
Jul 23 '05 #10

P: n/a
Matthias wrote:
[SNIP]
I just recognized that I can't cast because I'm using std::transform,
so I have no influence on the arguments passed. But since they come
from an std::string they are most probably valid characters right? =)


As far as I know in C and C++ by definition every character is valid. There
can be no values of char which are invalid, and all bits of char types (also
called bytes) must participate in the representation of its value. But I
guess that this does not answer your question, because your term of "valid
character" means something entirely different to you.

--
Attila aka WW
Jul 23 '05 #11

P: n/a
Matthias wrote:
Hello,

I am missing certain functionality of std::string, so I am currently
writing some helper functions which operate on strings. On of them is


Have you see Pavel Droba's string algorithm library at boost? See
http://www.boost.org/doc/html/string....html#id576916.

This offers an extensive set of well thought out algorithms. Boost is
extensively tested for portability across many platforms.

Jeff
Jul 23 '05 #12

P: n/a
Attila Feher wrote:
Matthias wrote:
[SNIP]
I just recognized that I can't cast because I'm using std::transform,
so I have no influence on the arguments passed. But since they come
from an std::string they are most probably valid characters right? =)

As far as I know in C and C++ by definition every character is valid. There
can be no values of char which are invalid, and all bits of char types (also
called bytes) must participate in the representation of its value. But I
guess that this does not answer your question, because your term of "valid
character" means something entirely different to you.

--
Attila aka WW


Well, if someone calls my function on a string which only contains
garbage characters, he shouldn't expect to retrieve anything but garbage
as well... :D

--
Regards,
Matthias
Jul 23 '05 #13

P: n/a
Jeff Flinn wrote:
Matthias wrote:
Hello,

I am missing certain functionality of std::string, so I am currently
writing some helper functions which operate on strings. On of them is

Have you see Pavel Droba's string algorithm library at boost? See
http://www.boost.org/doc/html/string....html#id576916.

This offers an extensive set of well thought out algorithms. Boost is
extensively tested for portability across many platforms.

Jeff


Thanks a lot. Everytime I miss something about the C++ language and I
think about writing my own stuff, somebody else has already done it. Heh.

--
Regards,
Matthias
Jul 23 '05 #14

P: n/a
Matthias wrote:

Ah, could have guessed that there is something like it... :)
I have a question though. I included <cctype> instead of <ctype.h>.
Now, I thought all those forwarding headers wrap the C-functions in the
namespace std? However, when I call std::tolower, I get an error that
this function doesn't exist. When calling without the namespace-prefix
it works just fine. Why ist that?

Do you mean that this does nor compile to you?
#include <iostream>
#include <cctype>
#include <vector>
#include <algorithm>
int main()
{
using namespace std;

string s="THiS iS a TeST STRiNG";

transform(s.begin(), s.end(), s.begin(), tolower);
}

However unfortunately this does not compile with MINGW GCC 3.3.1:
C:\c>g++ temp.cpp -o temp.exe
temp.cpp: In function `int main()':
temp.cpp:13: error: no matching function for call to `transform(
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >, <unknown type>)'
temp.cpp:16:1: warning: no newline at end of file

C:\c>
But compiles as it should with VC++:

C:\c>cl /EHsc temp.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.41013 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

temp.cpp
Microsoft (R) Incremental Linker Version 8.00.41013
Copyright (C) Microsoft Corporation. All rights reserved.

/out:temp.exe
temp.obj

C:\c>


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #15

P: n/a
Matthias wrote:
I just recognized that I can't cast because I'm using std::transform, so
I have no influence on the arguments passed. But since they come from an
std::string they are most probably valid characters right? =)

You do not need to cast anything during the tolower() call. You should
provide valid input in the first place, so if you place any checks you
should place them earlier in the string creation process.
Naturally if you input wrong data you will get undefined behaviour.
Casts during the call of tolower() can only hide invalid input which you
could notice afterwards.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #16

P: n/a
Ioannis Vranos wrote:
Do you mean that this does nor compile to you?

// Unneeded: #include <iostream>
#include <cctype>
#include <vector>
#include <algorithm>
int main()
{
using namespace std;

string s="THiS iS a TeST STRiNG";

transform(s.begin(), s.end(), s.begin(), tolower);
}

However unfortunately this does not compile with MINGW GCC 3.3.1:
C:\c>g++ temp.cpp -o temp.exe
temp.cpp: In function `int main()':
temp.cpp:13: error: no matching function for call to `transform(
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
__gnu_cxx::__normal_iterator<char*, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > >, <unknown type>)'
temp.cpp:16:1: warning: no newline at end of file

C:\c>
But compiles as it should with VC++:

C:\c>cl /EHsc temp.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.41013 for
80x86
Copyright (C) Microsoft Corporation. All rights reserved.

temp.cpp
Microsoft (R) Incremental Linker Version 8.00.41013
Copyright (C) Microsoft Corporation. All rights reserved.

/out:temp.exe
temp.obj

C:\c>


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #17

P: n/a
Ioannis Vranos wrote:
Matthias wrote:
I just recognized that I can't cast because I'm using std::transform, so I have no influence on the arguments passed. But since they come from an std::string they are most probably valid characters right? =)
You do not need to cast anything during the tolower() call. You

should provide valid input in the first place, so if you place any checks you should place them earlier in the string creation process.

Naturally if you input wrong data you will get undefined behaviour.
Casts during the call of tolower() can only hide invalid input which you could notice afterwards.


Consider the char whose value is -123. (In the usual character
set, this is an accented 'e' which is common in French). This is
most definitely a valid member of a std::string. But it is UB to
pass it to ctype.h's tolower() macro, because that macro expects
values in the range 0...255 (eg. it could be implemented as:
.. #define tolower(c) tolower_table[c]
where tolower_table is a 256-byte array of ints which have value
0 or 1).

However, the function std::tolower in <cctype> should accept
negative chars as input. Warning -- if you are using namespace
std; and you go: tolower(x), you might get the macro version on
a poorly-implemented library. So you should always explicitly
write std::tolower .

Jul 23 '05 #18

P: n/a
Old Wolf wrote:
However, the function std::tolower in <cctype> should accept
negative chars as input. Warning -- if you are using namespace
std; and you go: tolower(x), you might get the macro version on
a poorly-implemented library. So you should always explicitly
write std::tolower .


As I said, that doesn't work -- for whatever reason. I am getting an
error tolower() couldn't be found in the namespace std or something similar.

--
Regards,
Matthias
Jul 23 '05 #19

P: n/a
Matthias wrote:
As I said, that doesn't work -- for whatever reason. I am getting an
error tolower() couldn't be found in the namespace std or something
similar.

What compiler are you using? Doesn't this compile to your compiler?
#include <cctype>
#include <vector>
#include <algorithm>
int main()
{
using namespace std;

string s="THiS iS a TeST STRiNG";

transform(s.begin(), s.end(), s.begin(), tolower);
}


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #20

P: n/a
Ioannis Vranos wrote:
What compiler are you using? Doesn't this compile to your compiler?

#include <cctype>
#include <string>
#include <algorithm>
#include <iostream>
#include <ostream>

int main()
{
using namespace std;

string s="THiS iS a TeST STRiNG";

transform(s.begin(), s.end(), s.begin(), tolower);

cout<<s<<endl;
}

C:\c>cl /clr temp.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 14.00.41013
for Microsoft (R) .NET Framework version 2.00.41013.0
Copyright (C) Microsoft Corporation. All rights reserved.

temp.cpp
Microsoft (R) Incremental Linker Version 8.00.41013
Copyright (C) Microsoft Corporation. All rights reserved.

/out:temp.exe
temp.obj

C:\c>temp
this is a test string

C:\c>

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #21

This discussion thread is closed

Replies have been disabled for this discussion.