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

comparing two strcasecmp (stricmp) implementations

P: n/a
I'm currently evaluating two implementations of a case insensitive
string comparison function to replace the non-ANSI stricmp(). Both of
the implementations below seem to work fine but I'm wondering if one is
better than the other or if there is some sort of hybrid of the two
that would be superior.
IMPLEMENTATION 1:

#ifndef HAVE_STRCASECMP
#define ccmp(a,b) ((a) == (b) ? 0 : ((a) > (b) ? 1 : -1))
int strcasecmp(unsigned char *s1, unsigned char *s2)
{
unsigned char c1, c2;
for ( ; ; )
{
if (*s1 == '\0' || *s2 == '\0')
return ccmp(*s1,*s2);
c1= (isascii(*s1) && isupper(*s1)) ? (unsigned char) tolower(*s1) :
*s1;
c2= (isascii(*s2) && isupper(*s2)) ? (unsigned char) tolower(*s2) :
*s2;
if (c1 != c2)
return ccmp(c1,c2);
s1++;
s2++;
}
}
#undef ccmp
#endif
IMPLEMENTATION 2:

int strcasecmp(const char *s1, const char *s2)
{
unsigned char c1,c2;
do {
c1 = *s1++;
c2 = *s2++;
c1 = (unsigned char) tolower( (unsigned char) c1);
c2 = (unsigned char) tolower( (unsigned char) c2);
}
while((c1 == c2) && (c1 != '\0'));
return (int) c1-c2;
}

Nov 15 '05 #1
Share this Question
Share on Google+
88 Replies


P: n/a
William Krick wrote:
I'm currently evaluating two implementations of a case insensitive
string comparison function to replace the non-ANSI stricmp(). Both of
the implementations below seem to work fine but I'm wondering if one is
better than the other or if there is some sort of hybrid of the two
that would be superior.
IMPLEMENTATION 1:

#ifndef HAVE_STRCASECMP
#define ccmp(a,b) ((a) == (b) ? 0 : ((a) > (b) ? 1 : -1))
int strcasecmp(unsigned char *s1, unsigned char *s2)
{
unsigned char c1, c2;
for ( ; ; )
{
if (*s1 == '\0' || *s2 == '\0')
return ccmp(*s1,*s2);
c1= (isascii(*s1) && isupper(*s1)) ? (unsigned char) tolower(*s1) :
*s1;
c2= (isascii(*s2) && isupper(*s2)) ? (unsigned char) tolower(*s2) :
*s2;
if (c1 != c2)
return ccmp(c1,c2);
s1++;
s2++;
}
}
#undef ccmp
#endif
IMPLEMENTATION 2:

int strcasecmp(const char *s1, const char *s2)
{
unsigned char c1,c2;
do {
c1 = *s1++;
c2 = *s2++;
c1 = (unsigned char) tolower( (unsigned char) c1);
c2 = (unsigned char) tolower( (unsigned char) c2);
}
while((c1 == c2) && (c1 != '\0'));
return (int) c1-c2;
}


How about:

int strcasecmp( const char *s1, const char *s2 )
{
while (1)
{
int c1 = tolower( (unsigned char) *s1++ );
int c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2) return c1 - c2;
}
}

Doesn't reuse variables, doesn't have iffy casts, slightly shorter.
What have I missed?

--
Chris "one-track" Dollin
Capability does not imply necessity.
Nov 15 '05 #2

P: n/a
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top. I also changed it from while(1)
to for(;;) because the while was throwing a warning. However, while
this code works great in most cases, it doesn't handle NULL strings and
just blows up.

int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}

Nov 15 '05 #3

P: n/a
In article <11**********************@o13g2000cwo.googlegroups .com>,
William Krick <wk****@gmail.com> wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top.
Really? What C compilers are these?
I also changed it from while(1)
to for(;;) because the while was throwing a warning.
Definitely time for a new compiler!
However, while
this code works great in most cases, it doesn't handle NULL strings and
just blows up.


Since when were the str* functions supposed to handle NULL?

-- Richard
Nov 15 '05 #4

P: n/a
William Krick wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top.
You're not serious, surely. You have C compilers that don't allow
declarations in nested blocks? This is not a recent feature.
I also changed it from while(1)
to for(;;) because the while was throwing a warning.
Well, OK I suppose; but I'd be deeply suspicious of such a warning
myself (perhaps I used while(1) more than usual).
However, while
this code works great in most cases, it doesn't handle NULL strings and
just blows up.
There are no such things as NULL strings. There are null (empty) strings,
and there are null pointers, which are not any kind of string. If you mean
that it doesn't handle null pointer arguments, well no, it doesn't; it
does case-insensitive string compare, and NULL isn't a string. The user
should not call it with null pointer arguments.

(I can't think of a sensible answer to return for any null argument. If
you really really want to guard for this case, just add to the top

if (s1 == 0 || s2 == 0) return WHATEVERYOUWANT;

or wrap it as

if (s1 && s2) THEPREVIOUSCODE
else return WHATEVERYOUWANT;
)
int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}


--
Chris "one-track" Dollin
Capability does not imply necessity.
Nov 15 '05 #5

P: n/a

Chris Dollin wrote:
William Krick wrote:
However, while
this code works great in most cases, it doesn't handle NULL strings and
just blows up.


There are no such things as NULL strings. There are null (empty) strings,
and there are null pointers, which are not any kind of string. If you mean
that it doesn't handle null pointer arguments, well no, it doesn't; it
does case-insensitive string compare, and NULL isn't a string. The user
should not call it with null pointer arguments.

Point taken. This is my first foray back into C after being a Java
programmer for 5 years. I admit I'm VERY rusty.

I think Richard Tobin was right when he said...
"Since when were the str* functions supposed to handle NULL?"

I shouldn't be trying to handle null pointers.

Thanks for your help everyone.

Nov 15 '05 #6

P: n/a
Chris Dollin wrote:
William Krick wrote:

<snip>
However, while
this code works great in most cases, it doesn't handle NULL strings and
just blows up.

There are no such things as NULL strings. There are null (empty) strings,
and there are null pointers, which are not any kind of string. If you mean
that it doesn't handle null pointer arguments, well no, it doesn't; it
does case-insensitive string compare, and NULL isn't a string. The user
should not call it with null pointer arguments.

(I can't think of a sensible answer to return for any null argument. If
you really really want to guard for this case, just add to the top

if (s1 == 0 || s2 == 0) return WHATEVERYOUWANT;

I'd prefer

assert(s1 && s2);

Or a (documented) redefinition of the semantics (e.g., treat 0 as "").

You could use WHATEVERYOUWANT if you document either it or the fact that
passing null pointers will yield an indeterminate value. Don't keep it
under the hood, in any case.

S.
Nov 15 '05 #7

P: n/a
On Thu, 10 Nov 2005 17:27:47 +0000, Chris Dollin <ke**@hpl.hp.com>
wrote:
I also changed it from while(1)
to for(;;) because the while was throwing a warning.


Well, OK I suppose; but I'd be deeply suspicious of such a warning
myself (perhaps I used while(1) more than usual).


In my experience, this warning is quite common. The warning is that
the condition is always true. In more complex cases, it can be useful.

I seem to remember that we had a fairly lengthy thread about this not
long ago. Might have been a different NG.
--
Al Balmer
Balmer Consulting
re************************@att.net
Nov 15 '05 #8

P: n/a
William Krick wrote:

I'm currently evaluating two implementations of a case insensitive
string comparison function to replace the non-ANSI stricmp().
Both of
the implementations below seem to work fine
but I'm wondering if one is
better than the other or if there is some sort of hybrid of the two
that would be superior.


This is what I use:

int str_ccmp(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;

while (toupper(*p1) == toupper(*p2)) {
if (*p1 == '\0') {
return 0;
}
++p1;
++p2;
}
return toupper(*p2) > toupper(*p1) ? -1 : 1;
}

--
pete
Nov 15 '05 #9

P: n/a


pete wrote On 11/10/05 12:58,:
William Krick wrote:
I'm currently evaluating two implementations of a case insensitive
string comparison function to replace the non-ANSI stricmp().
Both of
the implementations below seem to work fine
but I'm wondering if one is
better than the other or if there is some sort of hybrid of the two
that would be superior.

This is what I use:

int str_ccmp(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;


These would be incorrect (or at the very least dubious)
on signed-magnitude or ones' complement machines. In the
Immortal Words (which someone reacently mis-attributed to
me; they're by Henry Spencer): "If you lie to the compiler,
it will have its revenge." The above are lies, so ...

--
Er*********@sun.com

Nov 15 '05 #10

P: n/a
Eric Sosman <er*********@sun.com> writes:
pete wrote On 11/10/05 12:58,:
int str_ccmp(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;


These would be incorrect (or at the very least dubious)
on signed-magnitude or ones' complement machines. [...]


What problem do you have in mind here?
--
"It would be a much better example of undefined behavior
if the behavior were undefined."
--Michael Rubenstein
Nov 15 '05 #11

P: n/a

William Krick wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top. I also changed it from while(1)
to for(;;) because the while was throwing a warning.

int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}

One final revision. I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...

int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 == c2 ? 0 : c1 > c2 ? 1 : -1;
}
}

Nov 15 '05 #12

P: n/a
William Krick wrote:
William Krick wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top. I also changed it from while(1)
to for(;;) because the while was throwing a warning.

int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}


One final revision. I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...

int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 == c2 ? 0 : c1 > c2 ? 1 : -1;
}
}


Aww, you ruined it. What next? Make it a do-while with a neat return at
the end?

S.
Nov 15 '05 #13

P: n/a
"William Krick" <wk****@gmail.com> writes:

[case-insensitive strcmp-like function]
I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...


strcmp() isn't specified so strictly. You can't depend on it
returning exactly -1 or 1. Here's what the standard says:

3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by
s1 is greater than, equal to, or less than the string
pointed to by s2.

--
"Some programming practices beg for errors;
this one is like calling an 800 number
and having errors delivered to your door."
--Steve McConnell
Nov 15 '05 #14

P: n/a


Ben Pfaff wrote On 11/10/05 13:49,:
Eric Sosman <er*********@sun.com> writes:

pete wrote On 11/10/05 12:58,:
int str_ccmp(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;


These would be incorrect (or at the very least dubious)
on signed-magnitude or ones' complement machines. [...]

What problem do you have in mind here?


char c = -1;
unsigned char *puc = (unsigned char*)&c;
printf ("%d ?= %d\n", (unsigned char)c, *puc);

Expected output (assuming 8-bit characters):

255 ?= 255 (two's complement)
255 ?= 129 (signed magnitude)
255 ?= 254 (ones' complement)

For the <ctype.h> functions, the argument corresponding to
the `char' whose value is -1 is `(int)UCHAR_MAX', always,
or 255 in the three cases above. Conversion from signed to
unsigned can involve more than just reinterpreting the bits.

--
Er*********@sun.com

Nov 15 '05 #15

P: n/a
Eric Sosman wrote:

Ben Pfaff wrote On 11/10/05 13:49,:
Eric Sosman <er*********@sun.com> writes:

pete wrote On 11/10/05 12:58,:

int str_ccmp(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;

These would be incorrect (or at the very least dubious)
on signed-magnitude or ones' complement machines. [...]

I disagree.
For the <ctype.h> functions, the argument corresponding to
the `char' whose value is -1 is `(int)UCHAR_MAX', always,
or 255 in the three cases above. Conversion from signed to
unsigned can involve more than just reinterpreting the bits.


The string functions are relevant here,
in particular, the comparison functions.

N869
7.21.4 Comparison functions
[#1] The sign of a nonzero value returned by the comparison
functions memcmp, strcmp, and strncmp is determined by the
sign of the difference between the values of the first pair
of characters (both interpreted as unsigned char) that
differ in the objects being compared.

--
pete
Nov 15 '05 #16

P: n/a


pete wrote On 11/10/05 15:30,:
Eric Sosman wrote:
Ben Pfaff wrote On 11/10/05 13:49,:
Eric Sosman <er*********@sun.com> writes:

pete wrote On 11/10/05 12:58,:
>int str_ccmp(const char *s1, const char *s2)
>{
> const unsigned char *p1 = (const unsigned char *)s1;
> const unsigned char *p2 = (const unsigned char *)s2;

These would be incorrect (or at the very least dubious)
on signed-magnitude or ones' complement machines. [...]

I disagree.

For the <ctype.h> functions, the argument corresponding to
the `char' whose value is -1 is `(int)UCHAR_MAX', always,
or 255 in the three cases above. Conversion from signed to
unsigned can involve more than just reinterpreting the bits.

The string functions are relevant here,
in particular, the comparison functions.

N869
7.21.4 Comparison functions
[#1] The sign of a nonzero value returned by the comparison
functions memcmp, strcmp, and strncmp is determined by the
sign of the difference between the values of the first pair
of characters (both interpreted as unsigned char) that
differ in the objects being compared.


Well, that's why I said "or at the very least dubious."
The characters being plucked from the string are handed as
arguments to tolower(), and the only requirement I can find
on the <ctype.h> argument values is 7.4/1:

"[...] the value of which shall be representable as
an unsigned char or shall equal the value of the
macro EOF."

The Standard is not entirely clear about what should
be done with negative `char' values. We know they need to
be made non-negative to become `unsigned char' values, but
is this to be done by conversion (my assumption) or by
reinterpretation (yours)? Nothing I can find in the Standard
or in the Rationale seems to shed any light. Hence "dubious"
rather than an unqualified "incorrect."

--
Er*********@sun.com

Nov 15 '05 #17

P: n/a
Eric Sosman wrote:
...
The Standard is not entirely clear about what should
be done with negative `char' values. We know they need to
be made non-negative to become `unsigned char' values, but
is this to be done by conversion (my assumption) or by
reinterpretation (yours)? Nothing I can find in the Standard
or in the Rationale seems to shed any light. Hence "dubious"
rather than an unqualified "incorrect."


Some previous queries by myself on the issue...

http://groups.google.com/group/comp....6b9c5072670cfd

http://groups.google.com/group/comp....9809d907620f55

--
Peter

Nov 15 '05 #18

P: n/a
On 2005-11-10, William Krick <wk****@gmail.com> wrote:

William Krick wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top. I also changed it from while(1)
to for(;;) because the while was throwing a warning.

int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}

One final revision. I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...


Such as which ones?

strcmp("foo","bar") returns 4 on my system, and probably yours. Only a
positive value is required by the standard in that case.
Nov 15 '05 #19

P: n/a
Eric Sosman wrote:

pete wrote On 11/10/05 15:30,:
of characters (both interpreted as unsigned char)

The Standard is not entirely clear about what should
be done with negative `char' values. We know they need to
be made non-negative to become `unsigned char' values, but
is this to be done by conversion (my assumption) or by
reinterpretation (yours)?


I'm seeing "interpreted as unsigned char"
in the above quote from the standard.
*(unsigned char *)byte, is the what "interpreted as" means.
The standard isn't shy about using the word "converted".

--
pete
Nov 15 '05 #20

P: n/a
pete wrote:

*(unsigned char *)byte, is the what "interpreted as" means.
*(unsigned char *)&byte
The standard isn't shy about using the word "converted".


--
pete
Nov 15 '05 #21

P: n/a
Ben Pfaff wrote
(in article <87************@benpfaff.org>):
"William Krick" <wk****@gmail.com> writes:

[case-insensitive strcmp-like function]
I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...


strcmp() isn't specified so strictly. You can't depend on it
returning exactly -1 or 1. Here's what the standard says:

3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by
s1 is greater than, equal to, or less than the string
pointed to by s2.


And what 'harm' does it do, relative to the standard, to
restrict it in such a fashion? Are there programs that depend
upon larger and smaller values being returned?
--
Randy Howard (2reply remove FOOBAR)
"The power of accurate observation is called cynicism by those
who have not got it." - George Bernard Shaw

Nov 15 '05 #22

P: n/a
Randy Howard <ra*********@FOOverizonBAR.net> writes:
Ben Pfaff wrote
(in article <87************@benpfaff.org>):
"William Krick" <wk****@gmail.com> writes:

[case-insensitive strcmp-like function]
I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...


strcmp() isn't specified so strictly. You can't depend on it
returning exactly -1 or 1. Here's what the standard says:

3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by
s1 is greater than, equal to, or less than the string
pointed to by s2.

And what 'harm' does it do, relative to the standard, to
restrict it in such a fashion? Are there programs that depend
upon larger and smaller values being returned?

Surely it's not any standard's responsibility to protect programs which
make incorrect assumptions about their working within that standard's
environment?

--
Chris.
Nov 15 '05 #23

P: n/a
Jordan Abel wrote:
strcmp("foo","bar") returns 4 on my system, and probably yours. Only a
positive value is required by the standard in that case.


No.

It might be required according to every character set
that you ever heard of,
but that result isn't required by the standard.

The values of 'f' and 'b' are implementation defined,
and there's nothing in the standard requiring either
one to be greater.

--
pete
Nov 15 '05 #24

P: n/a
On 2005-11-11, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
strcmp("foo","bar") returns 4 on my system, and probably yours. Only a
positive value is required by the standard in that case.


No.

It might be required according to every character set
that you ever heard of,
but that result isn't required by the standard.

The values of 'f' and 'b' are implementation defined,
and there's nothing in the standard requiring either
one to be greater.


....that's nitpicking. i meant that nothing is required of the result but
the sign in general.
Nov 15 '05 #25

P: n/a
pete wrote:
Eric Sosman wrote:
pete wrote On 11/10/05 15:30,:


of characters (both interpreted as unsigned char)


The Standard is not entirely clear about what should
be done with negative `char' values. We know they need to
be made non-negative to become `unsigned char' values, but
is this to be done by conversion (my assumption) or by
reinterpretation (yours)?

I'm seeing "interpreted as unsigned char"
in the above quote from the standard.
*(unsigned char *)byte, is the what "interpreted as" means.
The standard isn't shy about using the word "converted".


I do not subscribe to the idea that the Standard's
description of a Standard library function should govern
the design of non-Standard functions.

Besides, you haven't addressed the issue of the
argument values for <ctype.h> functions. Shy, schmy.

--
Eric Sosman
es*****@acm-dot-org.invalid

Nov 15 '05 #26

P: n/a
Eric Sosman wrote:

pete wrote:
Eric Sosman wrote:
pete wrote On 11/10/05 15:30,:
of characters (both interpreted as unsigned char)


The Standard is not entirely clear about what should
be done with negative `char' values.

I do not subscribe to the idea that the Standard's
description of a Standard library function should govern
the design of non-Standard functions.
Then what difference does it make to you
whether or not the Standard is entirely clear
about what should be done with negative `char' values?
Besides, you haven't addressed the issue of the
argument values for <ctype.h> functions. Shy, schmy.


It's all here:

*(const unsigned char *)s1 is the value of the byte.
That value is the argument to toupper.
I don't see why anything else would be better.

int str_ccmp(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;

while (toupper(*p1) == toupper(*p2)) {
if (*p1 == '\0') {
return 0;
}
++p1;
++p2;
}
return toupper(*p2) > toupper(*p1) ? -1 : 1;
}
--
pete
Nov 15 '05 #27

P: n/a
Jordan Abel wrote:

On 2005-11-11, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
strcmp("foo","bar") returns 4 on my system,
and probably yours. Only a
positive value is required by the standard in that case.


No.

It might be required according to every character set
that you ever heard of,
but that result isn't required by the standard.

The values of 'f' and 'b' are implementation defined,
and there's nothing in the standard requiring either
one to be greater.


...that's nitpicking.
i meant that nothing is required of the result but
the sign in general.


strcmp("foo","bar") is not required by
the standard to return a positive value.

You mean only that strcmp("foo","bar") should not return zero?

--
pete
Nov 15 '05 #28

P: n/a
On 2005-11-11, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:

On 2005-11-11, pete <pf*****@mindspring.com> wrote:
> Jordan Abel wrote:
>
>> strcmp("foo","bar") returns 4 on my system,
>> and probably yours. Only a
>> positive value is required by the standard in that case.
>
> No.
>
> It might be required according to every character set
> that you ever heard of,
> but that result isn't required by the standard.
>
> The values of 'f' and 'b' are implementation defined,
> and there's nothing in the standard requiring either
> one to be greater.


...that's nitpicking.
i meant that nothing is required of the result but
the sign in general.


strcmp("foo","bar") is not required by
the standard to return a positive value.

You mean only that strcmp("foo","bar") should not return zero?


I meant "If 'f' > 'b', then strcmp("foo","bar") is required to return a
positive number." And I thought that was perfectly clear.
Nov 15 '05 #29

P: n/a
Chris McDonald wrote
(in article <dl**********@enyo.uwa.edu.au>):
Randy Howard <ra*********@FOOverizonBAR.net> writes:
Ben Pfaff wrote
(in article <87************@benpfaff.org>):

"William Krick" <wk****@gmail.com> writes:

[case-insensitive strcmp-like function]

I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...

strcmp() isn't specified so strictly. You can't depend on it
returning exactly -1 or 1. Here's what the standard says:

3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by
s1 is greater than, equal to, or less than the string
pointed to by s2.

And what 'harm' does it do, relative to the standard, to
restrict it in such a fashion? Are there programs that depend
upon larger and smaller values being returned?

Surely it's not any standard's responsibility to protect programs which
make incorrect assumptions about their working within that standard's
environment?


I didn't say or imply that it was. As such, I don't understand
your question. All I said was that returning only three values
instead of a much larger range didn't seem like a problem from
here.
--
Randy Howard (2reply remove FOOBAR)
"The power of accurate observation is called cynicism by those
who have not got it." - George Bernard Shaw

Nov 15 '05 #30

P: n/a
Randy Howard <ra*********@FOOverizonBAR.net> writes:
Chris McDonald wrote
(in article <dl**********@enyo.uwa.edu.au>):
Randy Howard <ra*********@FOOverizonBAR.net> writes:
And what 'harm' does it do, relative to the standard, to
restrict it in such a fashion? Are there programs that depend
upon larger and smaller values being returned?

Surely it's not any standard's responsibility to protect programs which
make incorrect assumptions about their working within that standard's
environment?

I didn't say or imply that it was. As such, I don't understand
your question. All I said was that returning only three values
instead of a much larger range didn't seem like a problem from
here.


OK, sorry, we both agree
(without intonation, flat ASCII replies can get interpreted either way).

--
Chris.
Nov 15 '05 #31

P: n/a
On 10 Nov 2005 08:32:21 -0800, "William Krick" <wk****@gmail.com>
wrote in comp.lang.c:
I'm currently evaluating two implementations of a case insensitive
string comparison function to replace the non-ANSI stricmp(). Both of
the implementations below seem to work fine but I'm wondering if one is
better than the other or if there is some sort of hybrid of the two
that would be superior.
IMPLEMENTATION 1:

#ifndef HAVE_STRCASECMP
#define ccmp(a,b) ((a) == (b) ? 0 : ((a) > (b) ? 1 : -1))
int strcasecmp(unsigned char *s1, unsigned char *s2)


[snip]

You have quite a few useful replies, but I notice one thing nobody has
pointed out.

Since you seem to be concerned with "ANSI-ness", you should not be
defining external or even file scope identifiers that start with "str"
followed by a lower case letter, as they are reserved for the
implementation.

Consider 'str_casecmp'.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 15 '05 #32

P: n/a
"William Krick" <wk****@gmail.com> writes:
William Krick wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top. I also changed it from while(1)
to for(;;) because the while was throwing a warning.

int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}

One final revision. I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...

int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 == c2 ? 0 : c1 > c2 ? 1 : -1;
}
}


If the tests are written differently, the return values
might be somewhat clearer:

int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;
if( c1 == 0 ) return 0;
}
}
Incidentally, please use spaces rather than tabs when
posting to this newsgroup.
Nov 15 '05 #33

P: n/a
Jordan Abel wrote:
On 2005-11-11, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
On 2005-11-11, pete <pf*****@mindspring.com> wrote:

Jordan Abel wrote:
>strcmp("foo","bar") returns 4 on my system,
>and probably yours. Only a
>positive value is required by the standard in that case.

No.

It might be required according to every character set
that you ever heard of,
but that result isn't required by the standard.

The values of 'f' and 'b' are implementation defined,
and there's nothing in the standard requiring either
one to be greater.

...that's nitpicking.
i meant that nothing is required of the result but
the sign in general.


strcmp("foo","bar") is not required by
the standard to return a positive value.

You mean only that strcmp("foo","bar") should not return zero?


I meant "If 'f' > 'b', then strcmp("foo","bar") is required to return a
positive number." And I thought that was perfectly clear.


<commonsense>Yes, of course</commonsense>
<clc pedantic="true">No, you did not state it that way</clc>

I suggest you try to be a little more concise even in the
obvious cases and ignore or welcome the nits in the others.
The nits then tend to come as additional comments and not
outright contradiction... :-)

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 15 '05 #34

P: n/a
On 2005-11-11, Jack Klein <ja*******@spamcop.net> wrote:
On 10 Nov 2005 08:32:21 -0800, "William Krick" <wk****@gmail.com>
wrote in comp.lang.c:
I'm currently evaluating two implementations of a case insensitive
string comparison function to replace the non-ANSI stricmp(). Both of
the implementations below seem to work fine but I'm wondering if one is
better than the other or if there is some sort of hybrid of the two
that would be superior.
IMPLEMENTATION 1:

#ifndef HAVE_STRCASECMP
#define ccmp(a,b) ((a) == (b) ? 0 : ((a) > (b) ? 1 : -1))
int strcasecmp(unsigned char *s1, unsigned char *s2)


[snip]

You have quite a few useful replies, but I notice one thing nobody has
pointed out.

Since you seem to be concerned with "ANSI-ness", you should not be
defining external or even file scope identifiers that start with "str"
followed by a lower case letter, as they are reserved for the
implementation.

Consider 'str_casecmp'.


The HAVE_STRCASECMP macro presumably comes from a compile-time check on
whether the function exists. thus his code will only be reached on an
environment which has already been determined to be non-conforming.
Nov 15 '05 #35

P: n/a
Skarmander wrote:
Chris Dollin wrote:
William Krick wrote: <snip>
However, while
this code works great in most cases, it doesn't handle NULL strings and
just blows up.

There are no such things as NULL strings. There are null (empty) strings,
and there are null pointers, which are not any kind of string. If you
mean that it doesn't handle null pointer arguments, well no, it doesn't;
it does case-insensitive string compare, and NULL isn't a string. The
user should not call it with null pointer arguments.

(I can't think of a sensible answer to return for any null argument. If
you really really want to guard for this case, just add to the top

if (s1 == 0 || s2 == 0) return WHATEVERYOUWANT;

I'd prefer

assert(s1 && s2);


Well, it's a preference. It's not a very good guard, because if you
compile with NDEBUG it evaporates. I'm also not keen on programs that
can do an unavoidable BOOM, but this is C, so we're sort of stuck with
it.
Or a (documented) redefinition of the semantics (e.g., treat 0 as "").
Yes, you can do that. But I'd be very wary, because I think that a null
pointer should not be accepted as a string, and that redefinition of
the semantics licences it.

assert( s1 && s2 );
if (s1 == 0 || s2 == 0) yourLogFunction
( "A null pointer was passed to strcasecmp. Don't /do/ that. "
"It has been treated as the empty string. Don't rely on this." );
if (s1 == 0) s1 = "";
if (s2 == 0) s2 = "";
You could use WHATEVERYOUWANT if you document either it or the fact that
passing null pointers will yield an indeterminate value. Don't keep it
under the hood, in any case.


Oh, indeed; explicitness about the semantics (including "is undefined")
is desirable.

--
Chris "one-track" Dollin
Capability does not imply necessity.
Nov 15 '05 #36

P: n/a
Peter Nilsson wrote:

Eric Sosman wrote:
...
The Standard is not entirely clear about what should
be done with negative `char' values. We know they need to
be made non-negative to become `unsigned char' values, but
is this to be done by conversion (my assumption) or by
reinterpretation (yours)? Nothing I can find in the Standard
or in the Rationale seems to shed any light. Hence "dubious"
rather than an unqualified "incorrect."


Some previous queries by myself on the issue...


For negative int value arguments,
simple conversion to unsigned char seems appropriate,
for ctype functions.

The output functions, like putchar,
output their int value argument,
as though it were converted to unsigned char.

If you have a negative int value like:

#define NEG_A ('A' - 1 - (unsigned char)-1)

then,

putchar(NEG_A);

is going to output the 'A' character and return a value of 'A'.

tolower((unsigned char)NEG_A);

will return 'a'.

--
pete
Nov 15 '05 #37

P: n/a
Tim Rentsch wrote:
"William Krick" <wk****@gmail.com> writes:
William Krick wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top. I also changed it from while(1)
to for(;;) because the while was throwing a warning.

int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}

One final revision. I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...

int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 == c2 ? 0 : c1 > c2 ? 1 : -1;
}
}


If the tests are written differently, the return values
might be somewhat clearer:

int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;
if( c1 == 0 ) return 0;
}
}
Incidentally, please use spaces rather than tabs when
posting to this newsgroup.

Actually, when you cleaned up the return conditions, you left out some
of the conditions and broke the code. I've added them back in but I'm
sure it could still be simplified...

int str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if (c1 != c2 || c1 == 0) {
if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;
if( c1 == 0 ) return 0;
}
}
}

Nov 15 '05 #38

P: n/a
Tim Rentsch wrote:
"William Krick" <wk****@gmail.com> writes:
William Krick wrote:
To make the code compatible with older C compilers, I had to move the
declaration of c1 & c2 up to the top. I also changed it from while(1)
to for(;;) because the while was throwing a warning.

int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 - c2;
}
}

One final revision. I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...

int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 == c2 ? 0 : c1 > c2 ? 1 : -1;
}
}


If the tests are written differently, the return values
might be somewhat clearer:

int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;
if( c1 == 0 ) return 0;
}
}
Incidentally, please use spaces rather than tabs when
posting to this newsgroup.


Actually, when you cleaned up the return conditions, you left some of
them out and broke the code.

Here's an improved version using do-while as jokingly (I think)
suggested by Skarmander earlier in this thread...

int str_ccmp( const char *s1, const char *s2 ) {
int c1, c2;
do {
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
} while (c1 == c2 && c1 != 0);
return c1 - c2;
}

Nov 15 '05 #39

P: n/a
William Krick wrote:
Actually, when you cleaned up the return conditions, you left out some
of the conditions and broke the code. I've added them back in but I'm
sure it could still be simplified...

int str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if (c1 != c2 || c1 == 0) {
if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;
if( c1 == 0 ) return 0;
}
}
}


int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;

do {
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
} while (c1 == c2 && c1 != 0);
return c2 > c1 ? -1 : c1 > c2;
}

--
pete
Nov 15 '05 #40

P: n/a
William Krick wrote:
Here's an improved version using do-while as jokingly (I think)
suggested by Skarmander earlier in this thread...

int str_ccmp( const char *s1, const char *s2 ) {
int c1, c2;
do {
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
} while (c1 == c2 && c1 != 0);
return c1 - c2;
}


I got another one for you.

int str_cncmp(const char *s1, const char *s2, size_t n)

{
int c1, c2;

if (n != 0) {
do {
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
} while (c1 == c2 && c1 != '\0' && --n != 0);
}
return n != 0 ? c1 - c2 : 0;
}
--
pete
Nov 15 '05 #41

P: n/a
Eric Sosman wrote:
I do not subscribe to the idea that the Standard's
description of a Standard library function should govern
the design of non-Standard functions.

Besides, you haven't addressed the issue of the
argument values for <ctype.h> functions. Shy, schmy.


Upon further consideration, I think you made some good points.

--
pete
Nov 15 '05 #42

P: n/a
"William Krick" <wk****@gmail.com> writes:
Tim Rentsch wrote:
"William Krick" <wk****@gmail.com> writes: [snip]
One final revision. I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...

int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;
for(;;)
{
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
if (c1 == 0 || c1 != c2)
return c1 == c2 ? 0 : c1 > c2 ? 1 : -1;
}
}


If the tests are written differently, the return values
might be somewhat clearer:

int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;
if( c1 == 0 ) return 0;
}
}


Actually, when you cleaned up the return conditions, you left out some
of the conditions and broke the code. [snip]


If you look again I think you'll see that the posted function
does indeed work properly. Here is the same function with some
assertions added -- see if you agree.
int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;

assert( c1 == c2 );

if( c1 == 0 ) return 0;

assert( c1 == c2 && c1 != 0 );
}
}

Note that each of the 'return' statements is executed only if the
condition 'c1 != c2 || c1 == 0' is true, because of the 'if'
tests; it's not necessary to test for it separately.
Nov 15 '05 #43

P: n/a

In article <11*********************@z14g2000cwz.googlegroups. com>, "William Krick" <wk****@gmail.com> writes:

I think Richard Tobin was right when he said...
"Since when were the str* functions supposed to handle NULL?"

I shouldn't be trying to handle null pointers.


That's debatable. The standard str* functions aren't required to do
anything sensible with null arguments (whether the actual parameter
is NULL or any other form of a null pointer value), but that doesn't
mean you must refrain from doing so as well. There may be justifi-
cations that apply to the standard functions (such as pre-standard
implementations and implementation-specific performance tricks) which
don't apply to yours.

All the functions *I* write which take a pointer parameter (except
for a very few special cases) handle null pointers in some fashion,
either by explicitly permitting them in the interface or by returning
an error.

For a function like your "strcasecmp" (note that this name is
reserved to the implementation, and you should not use it), I can see
a few possibilities. One already suggested is to treat null pointers
as if they were pointers to empty strings. A small variation on that
is to consider null pointers equal, but less than any string,
including an empty string. Another is to treat them similarly to
NaNs: null pointers never compare equal to anything, including null
pointers, for the purpose of your function. You'll have to decide
what nonzero value to return in that case, of course. (Since you
have int as the return type, you might want to use something like
INT_MAX as the return value, to distinguish it from likely values for
any legitimate comparison.)

Variations on this topic have been rehashed many times over the years
here, and there are those who feel that violating the interface of a
user-defined function ought to stop a program in its tracks. Even if
I agreed (and I generally do not, for programs of any complexity), I
wouldn't rely on undefined behavior to do that - because, being
undefined, it can't be trusted to do so. If you want to abort the
program if strcasecmp gets a null pointer, that's what abort() is
for.

--
Michael Wojcik mi************@microfocus.com

I do not care to listen; obloquy injures my self-esteem and I am
skeptical of praise. -- Jack Vance
Nov 15 '05 #44

P: n/a
On 2005-11-11, Michael Wojcik <mw*****@newsguy.com> wrote:
That's debatable. The standard str* functions aren't required to do
anything sensible with null arguments (whether the actual parameter
is NULL or any other form of a null pointer value), but that doesn't
mean you must refrain from doing so as well. There may be justifi-
cations that apply to the standard functions (such as pre-standard
implementations and implementation-specific performance tricks) which
don't apply to yours.
It appears that he's writing a substitute intended to drop-in for
strcasecmp on systems that don't provide it.
All the functions *I* write which take a pointer parameter (except
for a very few special cases) handle null pointers in some fashion,
either by explicitly permitting them in the interface or by returning
an error.

For a function like your "strcasecmp" (note that this name is
reserved to the implementation, and you should not use it)


which is why it's #ifndef'd to only compile on systems that don't
provide it.
Nov 15 '05 #45

P: n/a
Ben Pfaff <bl*@cs.stanford.edu> writes:
"William Krick" <wk****@gmail.com> writes:

[case-insensitive strcmp-like function]
I've modified the return statement so that it
returns -1 / 0 / 1 to bring it in line with the behaviour of other
similar functions...


strcmp() isn't specified so strictly. You can't depend on it
returning exactly -1 or 1. Here's what the standard says:

3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by
s1 is greater than, equal to, or less than the string
pointed to by s2.


Which means that restricting the returned values to -1 / 0 / 1 is both
perfectly legal and perfectly unnecessary. If you've gone to any
extra effort to restrict the result to those values, I suggest that
that effort is wasted.

On the other hand, there might be some issues on systems where
sizeof(int)==1 (and, by implication, CHAR_BIT>=16). I'm too lazy to
track down the details.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #46

P: n/a
Jordan Abel <jm****@purdue.edu> writes:
On 2005-11-11, Jack Klein <ja*******@spamcop.net> wrote:

[...]
Since you seem to be concerned with "ANSI-ness", you should not be
defining external or even file scope identifiers that start with "str"
followed by a lower case letter, as they are reserved for the
implementation.

Consider 'str_casecmp'.


The HAVE_STRCASECMP macro presumably comes from a compile-time check on
whether the function exists. thus his code will only be reached on an
environment which has already been determined to be non-conforming.


Non-conforming to what? Standard C doesn't define a strcasecmp()
function<OT>, though POSIX does</OT>.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #47

P: n/a
On Sat, 12 Nov 2005 22:33:12 GMT, in comp.lang.c , Keith Thompson
<ks***@mib.org> wrote:
Jordan Abel <jm****@purdue.edu> writes:
On 2005-11-11, Jack Klein <ja*******@spamcop.net> wrote:[...]
Since you seem to be concerned with "ANSI-ness", you should not be
defining external or even file scope identifiers that start with "str"
followed by a lower case letter, as they are reserved for the
implementation.

Consider 'str_casecmp'.


The HAVE_STRCASECMP macro presumably comes from a compile-time check on
whether the function exists. thus his code will only be reached on an
environment which has already been determined to be non-conforming.


Non-conforming to what?


You guys have snipped too much of the original context for anyone to
tell.
Standard C doesn't define a strcasecmp()


.... and end users ae not allowed to.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 15 '05 #48

P: n/a
Tim Rentsch wrote:
"William Krick" <wk****@gmail.com> writes:
Tim Rentsch wrote:
"William Krick" <wk****@gmail.com> writes: [snip] > One final revision. I've modified the return statement so that it
> returns -1 / 0 / 1 to bring it in line with the behaviour of other
> similar functions...
>
> int str_ccmp( const char *s1, const char *s2 )
> {
> int c1, c2;
> for(;;)
> {
> c1 = tolower( (unsigned char) *s1++ );
> c2 = tolower( (unsigned char) *s2++ );
> if (c1 == 0 || c1 != c2)
> return c1 == c2 ? 0 : c1 > c2 ? 1 : -1;
> }
> }

If the tests are written differently, the return values
might be somewhat clearer:

int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;
if( c1 == 0 ) return 0;
}
}


Actually, when you cleaned up the return conditions, you left out some
of the conditions and broke the code. [snip]


If you look again I think you'll see that the posted function
does indeed work properly. Here is the same function with some
assertions added -- see if you agree.
int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;

assert( c1 == c2 );

if( c1 == 0 ) return 0;

assert( c1 == c2 && c1 != 0 );
}
}

Note that each of the 'return' statements is executed only if the
condition 'c1 != c2 || c1 == 0' is true, because of the 'if'
tests; it's not necessary to test for it separately.

I'll be damned. You're right. My bad.

Even though that is clearer, it would probably be a little slower since
there's 3 comparisons being done on each loop vs two in this version
that Pete posted...

int str_ccmp( const char *s1, const char *s2 )
{
int c1, c2;
do {
c1 = tolower( (unsigned char) *s1++ );
c2 = tolower( (unsigned char) *s2++ );
} while (c1 == c2 && c1 != 0);
return c2 > c1 ? -1 : c1 > c2;
}

Nov 15 '05 #49

P: n/a
William Krick wrote:

Tim Rentsch wrote:
"William Krick" <wk****@gmail.com> writes:
of the conditions and broke the code. [snip]


If you look again I think you'll see that the posted function
does indeed work properly. Here is the same function with some
assertions added -- see if you agree.
int
str_ccmp( const char *s1, const char *s2 ){
int c1, c2;

for( ; ; s1++, s2++ ){
c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 > c2 ) return 1;
if( c1 < c2 ) return -1;

assert( c1 == c2 );

if( c1 == 0 ) return 0;

assert( c1 == c2 && c1 != 0 );
}
}

Note that each of the 'return' statements is executed only if the
condition 'c1 != c2 || c1 == 0' is true, because of the 'if'
tests; it's not necessary to test for it separately.


I'll be damned. You're right. My bad.

Even though that is clearer,


Is it really clearer?
That's not the first thing that would pop into my head
after getting an explanation of how I read the code wrong.

--
pete
Nov 15 '05 #50

88 Replies

This discussion thread is closed

Replies have been disabled for this discussion.