473,396 Members | 2,055 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

comparing two strcasecmp (stricmp) implementations

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
88 21926

In article <sl********************@random.yi.org>, Jordan Abel <jm****@purdue.edu> writes:
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.


Yes, but I don't see that makes any difference to anything I wrote.
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.


So what? That identifier is still reserved to the implementation.
Perhaps the next revision of the implementation for that platform
*will* include it. Perhaps that implementation uses it for some
other purpose - it's not required to document that.

In any event, there's little to be gained by adding a nonstandard
function with a reserved name only on platforms where it doesn't
already exist. Write the function, give it a legal name, and use it
everywhere. Then there's no need to worry about checking to see
whether it's already defined on each platform and conditional
compilation. The code is cleaner and portable.

The only possible justification for using a version supplied with the
implementation is performance, and if case-insensitive string
comparisons are in a performance-critical code section, that suggests
a review of the design might be in order.

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

Ten or ten thousand, does it much signify, Helen, how we
date fantasmal events, London or Troy? -- Basil Bunting
Nov 15 '05 #51
On 2005-11-13, Michael Wojcik <mw*****@newsguy.com> wrote:

In article <sl********************@random.yi.org>, Jordan Abel <jm****@purdue.edu> writes:
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.


Yes, but I don't see that makes any difference to anything I wrote.
> 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.


So what? That identifier is still reserved to the implementation.


As function names in stdlib.h and string.h - they are not reserved for
any other purpose, and if it has been determined that the headers in
question don't contain that function name...

Cites: C89:
4.13.7
Function names that begin with str and a lower-case letter
(followed by any combination of digits, letters and underscore) may be
added to the declarations in the <stdlib.h> header.
4.13.8
Function names that begin with str , mem , or wcs and a lower-case
letter (followed by any combination of digits, letters and underscore)
may be added to the declarations in the <string.h> header.
Perhaps the next revision of the implementation for that platform
*will* include it.
At which point HAVE_STRCASECMP will presumably test true, since these
are generated by seeing if a test program trying to use it successfully
translates.
Perhaps that implementation uses it for some other purpose - it's not
required to document that.
It's not allowed to do that. The language of the standard only permits
implementations to use it as a function name, and only in stdlib.h or
string.h. Nowhere else and for no other purpose.
The only possible justification for using a version supplied with the
implementation is performance, and if case-insensitive string
comparisons are in a performance-critical code section, that suggests
a review of the design might be in order.

Nov 15 '05 #52
Jordan Abel wrote:
and if it has been determined that the headers in
question don't contain that function name...
Where are you reading that that has anything to do with anything?

Cites: C89:
4.13.7
Function names that begin with str and a lower-case letter
(followed by any combination of digits, letters and underscore) may be
added to the declarations in the <stdlib.h> header. 4.13.8
Function names that begin with str , mem , or wcs and a lower-case
letter (followed by any combination of digits, letters and underscore)
may be added to the declarations in the <string.h> header.


--
pete
Nov 15 '05 #53
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
and if it has been determined that the headers in
question don't contain that function name...


Where are you reading that that has anything to do with anything?


I'm saying that if the implementation does not use the identifier for
either of the two purposes it has been reserved for [as determined at
compile-time], then the program is free to use it.
Cites: C89:
4.13.7
Function names that begin with str and a lower-case letter
(followed by any combination of digits, letters and underscore) may be
added to the declarations in the <stdlib.h> header.

4.13.8
Function names that begin with str , mem , or wcs and a lower-case
letter (followed by any combination of digits, letters and underscore)
may be added to the declarations in the <string.h> header.

Nov 15 '05 #54
Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
and if it has been determined that the headers in
question don't contain that function name...


Where are you reading that that has anything to do with anything?


I'm saying that if the implementation does not use the identifier for
either of the two purposes it has been reserved for [as determined at
compile-time], then the program is free to use it.


Yes.
I'm saying, how do you figure that's true?

--
pete
Nov 15 '05 #55
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
> Jordan Abel wrote:
>
>> and if it has been determined that the headers in question don't
>> contain that function name...
>
> Where are you reading that that has anything to do with anything?


I'm saying that if the implementation does not use the identifier for
either of the two purposes it has been reserved for [as determined at
compile-time], then the program is free to use it.


Yes.
I'm saying, how do you figure that's true?


Because it's not a generally reserved identifier, only one that an
implementation is free to use for a specific purpose. If it is
determined that it does not use it for that purpose, where does the
standard say the user is forbidden to use it?
Nov 15 '05 #56
pete wrote:

Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:

> and if it has been determined that the headers in
> question don't contain that function name...

Where are you reading that that has anything to do with anything?


I'm saying that if the implementation does not use the identifier for
either of the two purposes it has been reserved for [as determined at
compile-time], then the program is free to use it.


Yes.
I'm saying, how do you figure that's true?


7.26 Future library directions

1 The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.

--
pete
Nov 15 '05 #57
Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
> Jordan Abel wrote:
>
>> and if it has been determined that the headers in question don't
>> contain that function name...
>
> Where are you reading that that has anything to do with anything?

I'm saying that if the implementation does not use the identifier for
either of the two purposes it has been reserved for [as determined at
compile-time], then the program is free to use it.


Yes.
I'm saying, how do you figure that's true?


Because it's not a generally reserved identifier, only one that an
implementation is free to use for a specific purpose. If it is
determined that it does not use it for that purpose, where does the
standard say the user is forbidden to use it?


7.26 Future library directions

1 The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.

7.26.11 String handling <string.h>
1 Function names that begin with str, mem,
or wcs and a lowercase letter may be added
to the declarations in the <string.h> header.

--
pete
Nov 15 '05 #58
pete wrote:

Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
>
> On 2005-11-14, pete <pf*****@mindspring.com> wrote:
> > Jordan Abel wrote:
> >
> >> and if it has been determined that the headers in question don't
> >> contain that function name...
> >
> > Where are you reading that that has anything to do with anything?
>
> I'm saying that if the implementation does not use the identifier for
> either of the two purposes it has been reserved for [as determined at
> compile-time], then the program is free to use it.

Yes.
I'm saying, how do you figure that's true?
Because it's not a generally reserved identifier, only one that an
implementation is free to use for a specific purpose. If it is
determined that it does not use it for that purpose, where does the
standard say the user is forbidden to use it?


2 If the program declares or defines an identifier in a
context in which it is reserved (other than as allowed by 7.1.4), or
defines a reserved identifier as a macro name,
the behavior is undefined.
7.26 Future library directions

1 The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.

7.26.11 String handling <string.h>
1 Function names that begin with str, mem,
or wcs and a lowercase letter may be added
to the declarations in the <string.h> header.


--
pete
Nov 15 '05 #59
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
pete wrote:

Jordan Abel wrote:
>
> On 2005-11-14, pete <pf*****@mindspring.com> wrote:
> > Jordan Abel wrote:
> >>
> >> On 2005-11-14, pete <pf*****@mindspring.com> wrote:
> >> > Jordan Abel wrote:
> >> >
> >> >> and if it has been determined that the headers in question don't
> >> >> contain that function name...
> >> >
> >> > Where are you reading that that has anything to do with anything?
> >>
> >> I'm saying that if the implementation does not use the identifier for
> >> either of the two purposes it has been reserved for [as determined at
> >> compile-time], then the program is free to use it.
> >
> > Yes.
> > I'm saying, how do you figure that's true?
>
> Because it's not a generally reserved identifier, only one that an
> implementation is free to use for a specific purpose. If it is
> determined that it does not use it for that purpose, where does the
> standard say the user is forbidden to use it?


2 If the program declares or defines an identifier in a context in
which it is reserved (other than as allowed by 7.1.4), or defines a
reserved identifier as a macro name, the behavior is undefined.
7.26 Future library directions

1 The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.

7.26.11 String handling <string.h>
1 Function names that begin with str, mem, or wcs and a lowercase
letter may be added to the declarations in the <string.h> header.


It's bad form to followup to yourself. And stop citing C99 at me, that's
not the standard in effect in 99% of implementations. I still see
"function names" [which refutes your 'could be using it for other
purposes' claim] and '_may_ be added' [which tells me that if they're
NOT added, they're ok to use].
Nov 15 '05 #60
Jordan Abel wrote:
And stop citing C99 at me, that's
not the standard in effect in 99% of implementations.
Good point!

7.1.3 Reserved identifiers
If the program declares or defines an identifier with the
same name as an identifier reserved in that context
(other than as allowed by 7.1.7), the behavior is undefined.

7.13 Future library directions
The following names are grouped under individual
headers for Convenience.
All external names described below are reserved
no matter what headers are included by the program.

7.13.8 String handling <string.h>
Function names that begin with str, mem,
or wcs and a lowercase letter
(followed by any combination of digits, letters, and underscore)
may be added to the declarations in the <string.h> header.

I still see
"function names" [which refutes your 'could be using it for other
purposes' claim] and '_may_ be added' [which tells me that if they're
NOT added, they're ok to use].


It tells me that function names starting with str are reserved,

"All external names described below are reserved "

and it doesn't say that they're not reserved
when they are not added.

There is no 'could be using it for other purposes' claim.

How does "function names" or anything else for that matter,
translate into permission to make declarations with
reserved identifiers?

--
pete
Nov 15 '05 #61
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
It tells me that function names starting with str are reserved,

"All external names described below are reserved "

and it doesn't say that they're not reserved
when they are not added.

There is no 'could be using it for other purposes' claim.

How does "function names" or anything else for that matter,
translate into permission to make declarations with
reserved identifiers?


It either is there or it's not. This is not a program that
unconditionally defines one, this is based on a test to see whether a
particular implementation allows it

Your reading would forbid third-party POSIX-compliance add-ons.
Nov 15 '05 #62
Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
It tells me that function names starting with str are reserved,

"All external names described below are reserved "

and it doesn't say that they're not reserved
when they are not added.
It either is there or it's not.
The standard is talking about undefined behavior
in terms of what's reserved, not in terms of what's there.
Your reading would forbid third-party POSIX-compliance add-ons.


Maybe.
POSIX isn't ANSI C, is it?
Didn't POSIX.1c redefine errno as a service?

--
pete
Nov 15 '05 #63
In article <sl********************@random.yi.org> Jordan Abel <jm****@purdue.edu> writes:
Jordan Abel wrote: ....
I'm saying that if the implementation does not use the identifier for
either of the two purposes it has been reserved for [as determined at
compile-time], then the program is free to use it.
.... Because it's not a generally reserved identifier, only one that an
implementation is free to use for a specific purpose. If it is
determined that it does not use it for that purpose, where does the
standard say the user is forbidden to use it?


In addition to other problems, I am wondering how you determine
(compile-time) whether some function has been defined in a header
or not. #ifdef works only for macros (it is in the preprocessor,
identifiers of functions are not in it).
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Nov 15 '05 #64
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
> It tells me that function names starting with str are reserved,
>
> "All external names described below are reserved "
>
> and it doesn't say that they're not reserved
> when they are not added.
It either is there or it's not.


The standard is talking about undefined behavior
in terms of what's reserved, not in terms of what's there.


because it's talking about a translation unit in isoltion
Your reading would forbid third-party POSIX-compliance add-ons.


Maybe.
POSIX isn't ANSI C, is it?
Didn't POSIX.1c redefine errno as a service?


eh?

posix doesn't define anything that conflicts with ansi c - what are you
on about?
Nov 15 '05 #65
On 2005-11-14, Dik T. Winter <Di********@cwi.nl> wrote:
In article <sl********************@random.yi.org> Jordan Abel <jm****@purdue.edu> writes:
> > Jordan Abel wrote: ... > >> I'm saying that if the implementation does not use the identifier for
> >> either of the two purposes it has been reserved for [as determined at
> >> compile-time], then the program is free to use it.

...
> Because it's not a generally reserved identifier, only one that an
> implementation is free to use for a specific purpose. If it is
> determined that it does not use it for that purpose, where does the
> standard say the user is forbidden to use it?


In addition to other problems, I am wondering how you determine
(compile-time) whether some function has been defined in a header
or not. #ifdef works only for macros (it is in the preprocessor,
identifiers of functions are not in it).


Attempt to compile a test program using it and see if it works. Put the
result in config.h and #include "config.h"
Nov 15 '05 #66
Jordan Abel wrote:
Your reading would forbid third-party POSIX-compliance add-ons.


Maybe.
POSIX isn't ANSI C, is it?
Didn't POSIX.1c redefine errno as a service?


eh?

posix doesn't define anything that conflicts with ansi c
- what are you on about?


POSIX.1c redefines errno as a service that
can access the per-thread error
number as follows (ISO/IEC 9945:1-1996, §2.4):

http://www.unix.org/whitepapers/reentrant.html

I don't think that citing whatever it is
you think you know about POSIX,
to validate your beliefs about ANSI C,
is appropriate.

--
pete
Nov 15 '05 #67
In article <sl********************@random.yi.org> Jordan Abel <jm****@purdue.edu> writes:
On 2005-11-14, Dik T. Winter <Di********@cwi.nl> wrote:

....
In addition to other problems, I am wondering how you determine
(compile-time) whether some function has been defined in a header
or not. #ifdef works only for macros (it is in the preprocessor,
identifiers of functions are not in it).


Attempt to compile a test program using it and see if it works. Put the
result in config.h and #include "config.h"


That is quite a bit more than "compile-time". And are you sure that your
test will not give you a false negative? I am pretty sure you can not be
confident about that. "autoconf" and "configure" in many cases will fail
to give something that can reliably be compiled and used.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Nov 15 '05 #68
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
>> Your reading would forbid third-party POSIX-compliance add-ons.
>
> Maybe.
> POSIX isn't ANSI C, is it?
> Didn't POSIX.1c redefine errno as a service?


eh?

posix doesn't define anything that conflicts with ansi c
- what are you on about?


POSIX.1c redefines errno as a service that
can access the per-thread error
number as follows (ISO/IEC 9945:1-1996, §2.4):

http://www.unix.org/whitepapers/reentrant.html


errno is permitted to be a macro. imagine

<errno.h>:
int *__get_this_threads_errno_location();
#define errno (*__get_this_threads_errno_location())
/* or, another possibility */
extern __attribute__((per_thread)) int errno;

how does this contradict ansi?
Nov 15 '05 #69
[on whether a program can use the identifiers "strcasecmp" or "stricmp"]
On 2005-11-14, pete <pf*****@mindspring.com> [and in a nested quote of an earlier article also by pete] wrote [text from the C99 standard
that says using these identifiers in the usual way is in fact undefined.]

In article <sl********************@random.yi.org>
Jordan Abel <jm****@purdue.edu> wrote:It's bad form to followup to yourself. And stop citing C99 at me, that's
not the standard in effect in 99% of implementations.
This wording is essentially unchanged from C89, however.
I still see "function names" [which refutes your 'could be using it
for other purposes' claim] and '_may_ be added' [which tells me that
if they're NOT added, they're ok to use].


There is a practical problem here, and it has in fact occurred in
the past (although I doubt it will occur with either the names
strcasecmp() or stricmp()). That is: several different "popular"
implementations will actually implement functions that have *the
same name* but *different arguments*.

A test that attempts to determine whether strcasecmp() exists might
then find that it does -- but the strcasecmp() that the implementation
provides might take three or four arguments, instead of two.

One would (in such case) be faced with two alternatives in a program
that uses:

#ifndef HAVE_STRCASECMP
int strcasecmp(const char *l, const char *r) { ... code ... }
#endif

One could (a) define HAVE_STRCASECMP, causing the program to use
the implementation's function -- which needs more than two arguments
so the calls do not work -- or (b) leave HAVE_STRCASECMP undefined,
causing the program to define a strcasecmp() that conflicts with
the implementation's function, which may in turn lead the implementation
to crash or otherwise behave badly.

Practically speaking, I doubt that this situation will actually
occur with the name "strcasecmp", as I noted above, it has in fact
occurred before with other functions, the classic example being
"itoa": some implementation-provided itoa() functions take one
argument, some take two, and some take three. (I have never seen
any that take four, although four would actually be reasonable.)
--
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.
Nov 15 '05 #70
pete <pf*****@mindspring.com> writes:
Jordan Abel wrote:
>> Your reading would forbid third-party POSIX-compliance add-ons.
>
> Maybe.
> POSIX isn't ANSI C, is it?
> Didn't POSIX.1c redefine errno as a service?


eh?

posix doesn't define anything that conflicts with ansi c
- what are you on about?


POSIX.1c redefines errno as a service that
can access the per-thread error
number as follows (ISO/IEC 9945:1-1996, §2.4):


C99 says that errno

expands to a modifiable lvalue that has type int, the value of
which is set to a positive error number by several library
functions. It is unspecified whether errno is a macro or an
identifier declared with external linkage.

--
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 #71
Jordan Abel <jm****@purdue.edu> writes:
[...]
It's bad form to followup to yourself.


Um, why? I've done it myself a number of times when I've thought of
something after I've posted a message.

--
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 #72
On 2005-11-14, Keith Thompson <ks***@mib.org> wrote:
Jordan Abel <jm****@purdue.edu> writes:
[...]
It's bad form to followup to yourself.


Um, why? I've done it myself a number of times when I've thought of
something after I've posted a message.


I guess my statement was based on a somewhat naive belief that supercede
would actually be likely to work - sorry
Nov 15 '05 #73
Jordan Abel wrote:

On 2005-11-14, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:
>> Your reading would forbid third-party POSIX-compliance add-ons.


I have nothing left from the C standard to show.
I don't really know enough about posix to discuss it.

--
pete
Nov 15 '05 #74
pete wrote:
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;
}


I still find the version I posted earlier to be clearer:
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;
}
}

mostly because the signt of an uninitialised variable makes my
guts ache (and because I see no merit, absent some /specific/
documentation, for working so hard on the return value).

If the scope rules for do/while were more useful, I'd use it;
but they aren't.

--
Chris "another virtual machine" Dollin
time is just space under pressure. squeeze!
Nov 15 '05 #75
Chris Dollin wrote:
I still find the version I posted earlier to be clearer:


We all think like that.

--
pete
Nov 15 '05 #76
pete wrote:
Chris Dollin wrote:
I still find the version I posted earlier to be clearer:


We all think like that.


That's not the impression I'm getting. By the way, I /did/
supply some reasons /why/; you're not /required/ to comment
on them, of course.

--
Chris "optionality is not prohibition" Dollin
time is just space under pressure. squeeze!
Nov 15 '05 #77
On Mon, 14 Nov 2005 00:53:28 +0000 (UTC), in comp.lang.c , Jordan Abel
<jm****@purdue.edu> wrote:
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
pete wrote:

7.26 Future library directions

1 The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.

7.26.11 String handling <string.h>
1 Function names that begin with str, mem, or wcs and a lowercase
letter may be added to the declarations in the <string.h> header.


It's bad form to followup to yourself. And stop citing C99 at me, that's
not the standard in effect in 99% of implementations.


Irrelevant, since C89 had essentially identical wording.
I still see
"function names" [which refutes your 'could be using it for other
purposes' claim] and '_may_ be added' [which tells me that if they're
NOT added, they're ok to use].


Not at all - how can you tell they're not there?
--
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 #78
On 2005-11-14, Mark McIntyre <ma**********@spamcop.net> wrote:
On Mon, 14 Nov 2005 00:53:28 +0000 (UTC), in comp.lang.c , Jordan Abel
<jm****@purdue.edu> wrote:
On 2005-11-14, pete <pf*****@mindspring.com> wrote:
pete wrote:

7.26 Future library directions

1 The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.

7.26.11 String handling <string.h>
1 Function names that begin with str, mem, or wcs and a lowercase
letter may be added to the declarations in the <string.h> header.


It's bad form to followup to yourself. And stop citing C99 at me, that's
not the standard in effect in 99% of implementations.


Irrelevant, since C89 had essentially identical wording.
I still see
"function names" [which refutes your 'could be using it for other
purposes' claim] and '_may_ be added' [which tells me that if they're
NOT added, they're ok to use].


Not at all - how can you tell they're not there?


The specific mechanism isn't particularly relevant, but in many cases if
a function is not provided by the implementation, or is not declared in
the header, it is possible [either always, or with implementation-specific
options] for the program to fail to translate.
Nov 15 '05 #79

In article <sl********************@random.yi.org>, Jordan Abel <jm****@purdue.edu> writes:
On 2005-11-13, Michael Wojcik <mw*****@newsguy.com> wrote:
In article <sl********************@random.yi.org>, Jordan Abel <jm****@purdue.edu> writes:
On 2005-11-11, Michael Wojcik <mw*****@newsguy.com> wrote:
> 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.


So what? That identifier is still reserved to the implementation.


As function names in stdlib.h and string.h - they are not reserved for
any other purpose, and if it has been determined that the headers in
question don't contain that function name...


Wrong. C90 7.13: "All external names described below are reserved
no matter what headers are included by the program"; 7.13.8: "Function
names beginning with str, ...".
Perhaps the next revision of the implementation for that platform
*will* include it.


At which point HAVE_STRCASECMP will presumably test true,


Now there's a compelling argument. "This is wrong, but presumably
it'll go away if it might cause a problem." Why not avoid the
problem in the first place?
since these
are generated by seeing if a test program trying to use it successfully
translates.


And you know that how?
Perhaps that implementation uses it for some other purpose - it's not
required to document that.


It's not allowed to do that. The language of the standard only permits
implementations to use it as a function name, and only in stdlib.h or
string.h. Nowhere else and for no other purpose.


Wrong. The identifier is reserved to the implementation. The
implementation *may* add it to string.h, but need not.

If the implementation does add it to string.h, it need not do what
the OP's function does.

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

Recently, they appeared at the reopening of the Brookdale Library,
luring passersby with the opportunity to be anonymously silly.
Nov 15 '05 #80
"William Krick" <wk****@gmail.com> writes:
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
[...]


Just a few quick reactions:

1. It's almost always better to put clarity concerns ahead of
concerns about micro-optimization.

2. We don't know that the generated code will have three
comparisons in the main path of the loop; it could be
optimized to only two (and not unreasonable to guess that
it might be).

3. Even if there are three conditional branches, they won't
necessarily run slower than two - depends on how the
branches are predicted, etc.

4. Performance decisions should be based on measurement.

5. Any differerence is highly unlikely to be on the critical
path. ("Premature optimization is the root of all evil.")
Nov 16 '05 #81
pete <pf*****@mindspring.com> writes:
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.


There is a subtlety around the test for c1 == 0. See if you like
this writing better:

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 && c2 == 0 ) return 0;
}
}

This might be read as:

Get a character from each string

If the first character is bigger, the first string is bigger
If the first character is smaller, the first string is smaller
If we've reached the end of both strings, they are equal

Otherwise, we don't know the result yet; go around the
loop and try the next characters...
The earlier version omitted the '&& c2 == 0', which works because
at that point in the code it will always be true if 'c1 == 0' is
true.
Nov 16 '05 #82
Tim Rentsch wrote:

pete <pf*****@mindspring.com> writes:
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.


There is a subtlety around the test for c1 == 0. See if you like
this writing better:

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 && c2 == 0 ) return 0;
}
}

This might be read as:

Get a character from each string

If the first character is bigger, the first string is bigger
If the first character is smaller, the first string is smaller
If we've reached the end of both strings, they are equal

Otherwise, we don't know the result yet; go around the
loop and try the next characters...

The earlier version omitted the '&& c2 == 0', which works because
at that point in the code it will always be true if 'c1 == 0' is
true.


I like this loop best:

do {
c1 = tolower((unsigned char)*s1++);
c2 = tolower((unsigned char)*s2++);
} while (c1 == c2 && c1 != '\0');

.... just keep looping while they're equal and not at the end.

follwed by

return c2 > c1 ? -1 : c2 != c1;

.... which is my prefered idiom for comparing int types
in a qsort compar function.

--
pete
Nov 16 '05 #83
pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote:

pete <pf*****@mindspring.com> writes:
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.


There is a subtlety around the test for c1 == 0. See if you like
this writing better:

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 && c2 == 0 ) return 0;
}
}

This might be read as:

Get a character from each string

If the first character is bigger, the first string is bigger
If the first character is smaller, the first string is smaller
If we've reached the end of both strings, they are equal

Otherwise, we don't know the result yet; go around the
loop and try the next characters...

The earlier version omitted the '&& c2 == 0', which works because
at that point in the code it will always be true if 'c1 == 0' is
true.


I like this loop best:

do {
c1 = tolower((unsigned char)*s1++);
c2 = tolower((unsigned char)*s2++);
} while (c1 == c2 && c1 != '\0');

... just keep looping while they're equal and not at the end.

follwed by

return c2 > c1 ? -1 : c2 != c1;

... which is my prefered idiom for comparing int types
in a qsort compar function.


The two loops correspond to two basically different approaches
to comparing the strings, namely

1. A finite loop that finds the terminal location, then
tests for appropriate result

2. An "infinite" loop thats tests to see if result is known
yet, and continues on if not.

The 'do{...}while' loop takes approach 1, and the 'for(;;s1++,s2++)'
loop takes approach 2. I don't think either approach is inherently
better than the other.

However, it's easier to turn a loop written using approach 2 into a
functional version that uses tail recursion and has no (explicit)
looping at all:

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

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

return str_ccmp( s1+1, s2+1 );
}

Most likely this version will run slower than the do...while approach,
because there are three compares done for each character. But it's
easy to rewrite it to use the same condition optimization that the
do...while loop does:

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

if( c1 != c2 ) return c1 < c2 ? -1 : 1;
if( c1 == 0 ) return 0;

return str_ccmp( s1+1, s2+1 );
}

Depending on the particulars of the compiler etc, a function written
like this one can run faster than an imperative do...while version,
especially in the case of comparing short strings that are equal.

Again, I don't claim either approach 1 or approach 2 is necessarily
better than the other. Each has its plusses and minusses. There
is something nice though about the functional version.
Dec 3 '05 #84
Tim Rentsch wrote:

pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote:
There is a subtlety around the test for c1 == 0. See if you like
this writing better:

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 && c2 == 0 ) return 0;
}
}

This might be read as:

Get a character from each string

If the first character is bigger, the first string is bigger
If the first character is smaller, the first string is smaller
If we've reached the end of both strings, they are equal

Otherwise, we don't know the result yet; go around the
loop and try the next characters...

The earlier version omitted the '&& c2 == 0', which works because
at that point in the code it will always be true if 'c1 == 0' is
true.


I like this loop best:

do {
c1 = tolower((unsigned char)*s1++);
c2 = tolower((unsigned char)*s2++);
} while (c1 == c2 && c1 != '\0');

... just keep looping while they're equal and not at the end.

follwed by

return c2 > c1 ? -1 : c2 != c1;

... which is my prefered idiom for comparing int types
in a qsort compar function.


The two loops correspond to two basically different approaches
to comparing the strings, namely

1. A finite loop that finds the terminal location, then
tests for appropriate result

2. An "infinite" loop thats tests to see if result is known
yet, and continues on if not.

The 'do{...}while' loop takes approach 1, and the 'for(;;s1++,s2++)'
loop takes approach 2. I don't think either approach is inherently
better than the other.

However, it's easier to turn a loop written using approach 2 into a
functional version that uses tail recursion and has no (explicit)
looping at all:


How about for turning it into str_cncmp?

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

--
pete
Dec 3 '05 #85
pete <pf******@mindspring.com> writes:
Tim Rentsch wrote:

pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote: There is a subtlety around the test for c1 == 0. See if you like
> this writing better:
>
> 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 && c2 == 0 ) return 0;
> }
> }
>
> This might be read as:
>
> Get a character from each string
>
> If the first character is bigger, the first string is bigger
> If the first character is smaller, the first string is smaller
> If we've reached the end of both strings, they are equal
>
> Otherwise, we don't know the result yet; go around the
> loop and try the next characters...
>
> The earlier version omitted the '&& c2 == 0', which works because
> at that point in the code it will always be true if 'c1 == 0' is
> true.

I like this loop best:

do {
c1 = tolower((unsigned char)*s1++);
c2 = tolower((unsigned char)*s2++);
} while (c1 == c2 && c1 != '\0');

... just keep looping while they're equal and not at the end.

follwed by

return c2 > c1 ? -1 : c2 != c1;

... which is my prefered idiom for comparing int types
in a qsort compar function.


The two loops correspond to two basically different approaches
to comparing the strings, namely

1. A finite loop that finds the terminal location, then
tests for appropriate result

2. An "infinite" loop thats tests to see if result is known
yet, and continues on if not.

The 'do{...}while' loop takes approach 1, and the 'for(;;s1++,s2++)'
loop takes approach 2. I don't think either approach is inherently
better than the other.

However, it's easier to turn a loop written using approach 2 into a
functional version that uses tail recursion and has no (explicit)
looping at all:


How about for turning it into str_cncmp?

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


Here's the infinite loop version:

int
str_cncmp( const char *s1, const char *s2, size_t n ){
int c1, c2;

for( ; ; s1++, s2++, n-- ){
if( n == 0 ) return 0;

c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 != c2 ) return c1 < c2 ? -1 : 1;

if( c1 == 0 ) return 0;
}
}
It should be easy enough to turn that into a tail recursive functional
(single assignment) version. Actually I wrote a functional version
straight away. For aesthetic reasons I wanted the two 'return 0;'
statements combined into just one, and wanted to do that with no extra
compares, hence:

int
str_cncmp( const char *const a, const char *const b, const size_t n ){
unsigned char ua, ub;
int ca, cb;

if( n == 0 || ((ua = *a) | (ub = *b)) == 0 ) return 0;

ca = tolower( ua ), cb = tolower( ub );
if( ca != cb ) return ca < cb ? -1 : 1;

return str_cncmp( a+1, b+1, n-1 );
}
This functional version can "back produce" an iterative one:

int
str_cncmp( const char *a, const char *b, size_t n ){
unsigned char ua, ub;
int ca, cb;

while( n-- > 0 && (ua = *a++) | (ub = *b++) ){
ca = tolower( ua ), cb = tolower( ub );
if( ca != cb ) return ca < cb ? -1 : 1;
}

return 0;
}
All the above just typed in; no compiles done, nor any performance
tuning.
Dec 6 '05 #86
Tim Rentsch wrote:
Here's the infinite loop version:

int
str_cncmp( const char *s1, const char *s2, size_t n ){
int c1, c2;

for( ; ; s1++, s2++, n-- ){
if( n == 0 ) return 0;

c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 != c2 ) return c1 < c2 ? -1 : 1;

if( c1 == 0 ) return 0;
}
}
I think the above one is easier to read.
It should be easy enough to turn that into a tail recursive functional
(single assignment) version. Actually I wrote a functional version
straight away. For aesthetic reasons I wanted the two 'return 0;'
statements combined into just one, and wanted to do that with no extra
compares, hence:

int
str_cncmp( const char *const a, const char *const b, const size_t n ){
unsigned char ua, ub;
int ca, cb;

if( n == 0 || ((ua = *a) | (ub = *b)) == 0 ) return 0;

ca = tolower( ua ), cb = tolower( ub );
if( ca != cb ) return ca < cb ? -1 : 1;

return str_cncmp( a+1, b+1, n-1 );
}


--
pete
Dec 6 '05 #87
pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote:
Here's the infinite loop version:

int
str_cncmp( const char *s1, const char *s2, size_t n ){
int c1, c2;

for( ; ; s1++, s2++, n-- ){
if( n == 0 ) return 0;

c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 != c2 ) return c1 < c2 ? -1 : 1;

if( c1 == 0 ) return 0;
}
}


I think the above one is easier to read.


Not too surprising, since both the style and the paradigm are probably
more familiar. However, if you really want to understand the other
paradigm, what you should do is take imperative/iterative code in your
own style and write it functionally in your own style. For a while of
course imperative versions will seem more natural; but after you get
used to writing functional versions I expect you'll find they provide
equal clarity in many cases, and better in some. The point really is
to have both paradigms available; neither one is better in all cases.
Dec 8 '05 #88
Tim Rentsch wrote:

pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote:
Here's the infinite loop version:

int
str_cncmp( const char *s1, const char *s2, size_t n ){
int c1, c2;

for( ; ; s1++, s2++, n-- ){
if( n == 0 ) return 0;

c1 = tolower( (unsigned char) *s1 );
c2 = tolower( (unsigned char) *s2 );

if( c1 != c2 ) return c1 < c2 ? -1 : 1;

if( c1 == 0 ) return 0;
}
}


I think the above one is easier to read.


Not too surprising, since both the style and the paradigm are probably
more familiar.


And you'll see me posting similar versions in the future
without attribution. ;)

--
pete
Dec 9 '05 #89

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: xuatla | last post by:
Hi, I want to compare two strings regardless of the lowercase or uppercase. For example, "txt" same as "TXT", "Txt", ... I know that there's stricmp in some c++ that can perform a lowercase...
41
by: Odd-R. | last post by:
I have to lists, A and B, that may, or may not be equal. If they are not identical, I want the output to be three new lists, X,Y and Z where X has all the elements that are in A, but not in B, and...
18
by: jamihuq | last post by:
I'm trying to use strdup, strnicmp and stricmp in an OS that doesn't have an implementation in the OSs string.h function. Does someone have the implementation for these functions and can you please...
2
by: Michael Sgier | last post by:
Hi in linux i get the error stricmp not found or something like that. i only find strcmp in /usr/include what is the difference? can i use that? or what do i need to do with the above error?...
25
by: J Caesar | last post by:
In C you can compare two pointers, p<q, as long as they come from the same array or the same malloc()ated block. Otherwise you can't. What I'd like to do is write a function int comparable(void...
18
by: Carramba | last post by:
Hi! is there a better/faster way to compare mantissas of to real number then in following code? #include <stdio.h> #include <stdlib.h> int main(void) { float a,b; int test;
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.