according to MS, stricmp is deprecated

L

Lynn McGuire

According to Microsoft Visual C++ 2005, stricmp
is deprecated and they want us to use _stricmp.

Does anyone know why?

Does anyone recommend a good replacement?

Thanks,
Lynn McGuire
 
L

Lynn McGuire

As the MS note says, stricmp() is not a standard C function. As it
uses a namespace (functions starting with "str") reserved for the
standard, they removed it (sort of). Although MS mentions that it's a
Posix function, I don't think that's actually true.

If you're programming for Windows, use the version with the
underscore. If you port to a *nix system, you'll probably want to use
strcasecmp instead, although some do provide a (_)stricmp function.

This particular code runs on both Windows and
Unix. I was hoping that that MS supported a
strcasecmp function but VS 2005 does not.

Thanks,
Lynn
 
L

Lynn McGuire

In general these 'deprecated' warnings seem to be yet another attempt by MS
to force people in writing unportable code. In the case of stricmp()
however it is an overkill as stricmp() itself is already unportable (the
POSIX name is strcasecmp()).

The best way to fight with this is to use:

#ifdef _MSC_VER
inline int strcasecmp(const char* a, const char* b) {
return _stricmp(a, b);
}
#endif

and use strcasecmp() in your code. This will make it *more* portable!

Cheers
Paavo

Thanks, I like that !

Lynn
 
J

James Kanze

According to Microsoft Visual C++ 2005, stricmp
is deprecated and they want us to use _stricmp.
Does anyone know why?

My immediate reaction would be: how do you deprecate something that
never existed? There isn't, and never has been, such a function in
standard C or C++. It is, never the less, a wide spread extension; many
implementations even put it in <string.h> (which is in violation of the
standard). In the case of Microsoft, I think that they are simply
trying to clean up <string.h>, by removing all functions which aren't
allowed to be their, and renaming them with names the standard allows
implementations to use.
Does anyone recommend a good replacement?

The error message gives one. Since any use is implementation dependent.
(Even when several implementations provide it, you have no guarantee
that they will provide the same semantics.)
 
G

Geoff

This particular code runs on both Windows and
Unix. I was hoping that that MS supported a
strcasecmp function but VS 2005 does not.

Thanks,
Lynn

I've been using this for years on a project that works in Windows and
Linux. (VS 6.0 to VS 2010 and a long list of GCC versions.

/* old non-standard lib function to new non-standard lib function */
#ifdef _WIN32
#define stricmp _stricmp
#endif
 
G

Geoff

This particular code runs on both Windows and
Unix. I was hoping that that MS supported a
strcasecmp function but VS 2005 does not.

Thanks,
Lynn
That is fixable.

#ifdef _WIN32
#include <ctype.h>

int strcasecmp(const char *s1, const char *s2)
{
const unsigned char
*uc1 = (const unsigned char *)s1,
*uc2 = (const unsigned char *)s2;

while (tolower(*uc1) == tolower(*uc2++))
if (*uc1++ == '\0')
return (0);
return (tolower(*uc1) - tolower(*--uc2));
}
#endif

I don't know if this conforms to the current standard for strcasecmp.
 
G

Geoff

What's wrong with an inline forwarding function?

Nothing. As it is, I got off my ass this weekend and eliminated the
rename and implemented the strcasecmp function within the application,
conditional on _WIN32 as I posted here earlier. A hack is a hack and
it was time to eliminate that one.

Since we're in comp.lang.c++, what do you think of this implementation
of a case-insensitive compare of C++ strings?

int stringcasecmp(const std::string s1, const std::string s2)
{
std::string us1 = s1;
std::string us2 = s2;
std::transform(us1.begin(), us1.end(), us1.begin(), ::tolower);
std::transform(us2.begin(), us2.end(), us2.begin(), ::tolower);
return us1.compare(us2);
}

Improvements?
 
G

Geoff

Why wouldn't you add

int casecompare(const string &str) const
int casecompare(size_t, size_t, const string &) const;
int casecompare(size_t, size_t, const char *) const;

et alia (analogs to std::string::compare methods)

members to std::string?

std::string s;
std::string t;

if (s.casecompare(t) == 0) ...
if (s.casecompare(1, std::string::npos, "Testing") == 0) ...

Indeed I would. Do you have any recommendations for how to implement
them?
 
G

Geoff

Nothing. As it is, I got off my ass this weekend and eliminated the
rename and implemented the strcasecmp function within the application,
conditional on _WIN32 as I posted here earlier. A hack is a hack and
it was time to eliminate that one.

Since we're in comp.lang.c++, what do you think of this implementation
of a case-insensitive compare of C++ strings?

int stringcasecmp(const std::string s1, const std::string s2)
{
std::string us1 = s1;
std::string us2 = s2;
std::transform(us1.begin(), us1.end(), us1.begin(), ::tolower);
std::transform(us2.begin(), us2.end(), us2.begin(), ::tolower);
return us1.compare(us2);
}

This calls C function tolower(int), which has undefined behavior in case
of negative arguments. As the plain char type used by std::string is
often a signed type it can easily contain negative values. So this
implementation seems quite dangerous.

Even if the correct C++ std::tolower() function were used, it could not
properly support multibyte characters like UTF-8 encoding. I am even not
talking about comparing German ß and SS.

It also makes copies of the both strings (twice, as the parameters are
not references), then makes two passes through both strings, which may
become suboptimal if the strings do not fit in the cpu caches.

As the above function basically works only for ASCII (never seen EBCDIC
in real life), it would be best to acknowledge this; then calling the
locale-specific ::tolower would be wrong and also not necessary. Improved
version:

int strcasecmp_ascii(const std::string& s1, const std::string& s2)
{
const std::string::size_type n = std::min(s1.length(), s2.length());
for (std::string::size_type i = 0; i<n; ++i) {
char c1 = s1, c2=s2;
if (c1>='A' && c1<='Z') {
c1+=32;
}
if (c2>='A' && c2<='Z') {
c2+=32;
}
if (c1<c2) {
return -1;
} else if (c1>c2) {
return 1;
}
}
return s1.length()>n? 1: (s2.length()>n? -1: 0);
}


I wouldn't call that an improvement.

I would modify mine to eliminate your objections about unnecessary
copies of the strings. The goal was to make it non destructive of the
original strings.

//headers needed for implementing this function
#include <string>
#include <algorithm>
#include <locale.h>

int stringcasecmp(std::string s1, std::string s2)
{
std::transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
std::transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
return s1.compare(s2);
}

Which makes it work if the locale is set to a language other than
English. Since any program at any given time is perforce confined to a
given locale, I don't see a problem with using tolower in this
specific instance. The original goal of this function was to apply the
admittedly flawed principles of C's strcasecmp() to C++ strings and
strcasecmp calls tolower() and I have never seen one that solves the
general locale-independent problem. Your concern about UTF and signed
char types is worrisome and I don't have an immediate solution.

You make a cogent argument for a general solution to the problem but
you don't offer one. Since the standard doesn't provide a case
insensitive compare member, perhaps there is no satisfactory general
solution.
 
G

Geoff

On Sun, 28 Apr 2013 01:23:20 -0500, Paavo Helde

What's wrong with an inline forwarding function?

Nothing. As it is, I got off my ass this weekend and eliminated the
rename and implemented the strcasecmp function within the
application, conditional on _WIN32 as I posted here earlier. A hack
is a hack and it was time to eliminate that one.

Since we're in comp.lang.c++, what do you think of this
implementation of a case-insensitive compare of C++ strings?

int stringcasecmp(const std::string s1, const std::string s2)
{
std::string us1 = s1;
std::string us2 = s2;
std::transform(us1.begin(), us1.end(), us1.begin(), ::tolower);
std::transform(us2.begin(), us2.end(), us2.begin(), ::tolower);
return us1.compare(us2);
}

This calls C function tolower(int), which has undefined behavior in
case of negative arguments. As the plain char type used by std::string
is often a signed type it can easily contain negative values. So this
implementation seems quite dangerous.

Even if the correct C++ std::tolower() function were used, it could
not properly support multibyte characters like UTF-8 encoding. I am
even not talking about comparing German ß and SS.

It also makes copies of the both strings (twice, as the parameters are
not references), then makes two passes through both strings, which may
become suboptimal if the strings do not fit in the cpu caches.

As the above function basically works only for ASCII (never seen
EBCDIC in real life), it would be best to acknowledge this; then
calling the locale-specific ::tolower would be wrong and also not
necessary. Improved version:

int strcasecmp_ascii(const std::string& s1, const std::string& s2)
{
const std::string::size_type n = std::min(s1.length(), s2.length());
for (std::string::size_type i = 0; i<n; ++i) {
char c1 = s1, c2=s2;
if (c1>='A' && c1<='Z') {
c1+=32;
}
if (c2>='A' && c2<='Z') {
c2+=32;
}
if (c1<c2) {
return -1;
} else if (c1>c2) {
return 1;
}
}
return s1.length()>n? 1: (s2.length()>n? -1: 0);
}


I wouldn't call that an improvement.

I would modify mine to eliminate your objections about unnecessary
copies of the strings. The goal was to make it non destructive of the
original strings.

//headers needed for implementing this function
#include <string>
#include <algorithm>
#include <locale.h>

int stringcasecmp(std::string s1, std::string s2)
{
std::transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
std::transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
return s1.compare(s2);
}


This is still ignoring the undefined behavior of ::tolower with negative
values. See http://www.unix.com/man-page/POSIX/3posix/tolower/.
You make a cogent argument for a general solution to the problem but
you don't offer one.

I'm not quite sure what the problem is. If it is just implementing
strcasecmp() on Windows, then one can just forward to _stricmp() or
better yet to _wcsicmp().


This advice is amusing because Microsoft's _stricmp() and _wcsicmp()
both use ascii and wide versions of tolower().
If it is about implementing it without using the C portion of the C++
standard then you have failed as ::tolower is a C function as well.

No, it's not about that at all.
If it is about providing a general solution of case insensitive string
comparison then this has been already long done as strcasecmp() is part
of POSIX.

This is also amusing because the POSIX documentation states it is both
locale specific and depends on the tolower conversion.

http://pubs.opengroup.org/onlinepubs/9699919799/

"...

The strcasecmp() and strncasecmp() functions use the current locale to
determine the case of the characters.

The strcasecmp_l() and strncasecmp_l() functions use the locale
represented by locale to determine the case of the characters.

When the LC_CTYPE category of the locale being used is from the POSIX
locale, these functions shall behave as if the strings had been
converted to lowercase and then a byte comparison performed.
Otherwise, the results are unspecified.

The behavior is undefined if the locale argument to strcasecmp_l() or
strncasecmp_l() is the special locale object LC_GLOBAL_LOCALE or is
not a valid locale object handle."

All the implementations strcasecmp() I have been able to find trace
their parentage to BSD 4.3 from 1993 to wit:

int strcasecmp(const char *s1, const char *s2)
{
const unsigned char
*uc1 = (const unsigned char *)s1,
*uc2 = (const unsigned char *)s2;

while (tolower(*uc1) == tolower(*uc2++))
if (*uc1++ == '\0')
return (0);
return (tolower(*uc1) - tolower(*--uc2));
}
 
J

James Kanze

On Sun, 28 Apr 2013 01:23:20 -0500, Paavo Helde
Nothing. As it is, I got off my ass this weekend and eliminated the
rename and implemented the strcasecmp function within the application,
conditional on _WIN32 as I posted here earlier. A hack is a hack and
it was time to eliminate that one.
Since we're in comp.lang.c++, what do you think of this implementation
of a case-insensitive compare of C++ strings?
int stringcasecmp(const std::string s1, const std::string s2)
{
std::string us1 = s1;
std::string us2 = s2;
std::transform(us1.begin(), us1.end(), us1.begin(), ::tolower);
std::transform(us2.begin(), us2.end(), us2.begin(), ::tolower);
return us1.compare(us2);
}

For starters, it has undefined behavior: you can't call
::tolower on a char.

Performance-wise, of course: is there really any reason to build
two new strings? Wouldn't it be a lot better if you did the
transformations on the fly? (I'm supposing the fact that you
use pass by value, rather than references, is an oversight.)

And perhaps above all: what is the program really supposed to
do? (In most contexts, today, I would want it to handle UTF-8.
Obviously, this one doesn't, but what about "MASSE" vs. "Maße"?)
Shouldn't it be locale sensitive?

Part of the problem (and perhaps the reason why C and C++ didn't
adopt anything similar) is because case-insensitive compare
isn't really a well defined concept.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top