//code #1
string input = "yes";
if (input == "yes")
cout << "yes";
else
cout << "no";
//code #2
string input = "yes";
const char* str = input.c_str();
if (strcmp(str, "yes") == 0)
cout << "yes";
else
cout << "no";
//code #3
char* s = "yes";
if (s == "yes")
cout << "yes";
else
cout << "no";
//code #4
char* s = "yes";
if (strcmp(s, "yes") == 0)
cout << "yes";
else
cout << "no";
Homework? Hint. One of the four methods will give the wrong answer much of
the time (i.e., if you change the structure of the problem just slightly).
It isn't testing what you think it is testing.
--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)
All of them except 3 are (more or less) correct.
> The first two are C++ code, and the last two are C code, but they all
> yield the same result.
>
> //code #1
> string input = "yes";
> if (input == "yes")
> cout << "yes";
> else
> cout << "no";
>
> //code #2
> string input = "yes";
> const char* str = input.c_str();
> if (strcmp(str, "yes") == 0)
better to use
if (strcmp(input.c_str(), "yes") == 0)
Because that way you are less likely to use str when it is no longer valid.
> cout << "yes";
> else
> cout << "no";
>
> //code #3
> char* s = "yes";
> if (s == "yes")
WRONG. This compares pointers not strings.
This is not gauranteed as you are relying on constant folding.
If you put the assignment to s in another source file it would almost
certainly
print "no".
> cout << "yes";
> else
> cout << "no";
>
> //code #4
> char* s = "yes";
const char* s = "yes";
// char* is defined to work but it is a bad idea as s[2] = 'x' would compile
but the behaviour is undefined.
> if (strcmp(s, "yes") == 0)
> cout << "yes";
> else
> cout << "no";
The most efficient in general would be
static const string YES("yes");
if( input == YES )
....
This will work whether input is char* or string.
It will usually be slightly quicker where input is a string of length != 3
as most implementations
will do a quick length check before calling memcmp
> > //code #1
> > string input = "yes";
> > if (input == "yes")
> > cout << "yes";
> > else
> > cout << "no";
My preference in C++.
> > //code #2
> > string input = "yes";
> > const char* str = input.c_str();
> > if (strcmp(str, "yes") == 0)
>
> better to use
> if (strcmp(input.c_str(), "yes") == 0)
> Because that way you are less likely to use str when it is no longer
valid.
Also, c_str() forces construction of the C style representation of the
string, which will cause performance overhead on a representation that
naturally stores strings as an array of substrings. I know of no such
implementation, though I thought there was a rope class out there.
> The most efficient in general would be
> static const string YES("yes");
> if( input == YES )
> ....
> This will work whether input is char* or string.
I usuall use global variables, as the static variable I think inserts code
to check if the object is constructed.
namespace { const string YES("yes"); }
void f () {
if (input == YES) ;
}
> It will usually be slightly quicker where input is a string of length != 3
> as most implementations
> will do a quick length check before calling memcmp
Really. You mean they don't just call strcmp? Interesting stuff.
I meant it to be at file scope which is the same as global.
>
> namespace { const string YES("yes"); }
> void f () {
> if (input == YES) ;
> }
>
>
> > It will usually be slightly quicker where input is a string of length !=
3
> > as most implementations
> > will do a quick length check before calling memcmp
>
> Really. You mean they don't just call strcmp? Interesting stuff.
To be honest - I don't really know but I would be surprised and dissapointed
if they
didn't because they definitely keep the size and can access it with an
inline method
making the potential saving over a function call compartively large.
> > > It will usually be slightly quicker where input is a string of length
!=
> 3
> > > as most implementations
> > > will do a quick length check before calling memcmp
> >
> > Really. You mean they don't just call strcmp? Interesting stuff.
>
> To be honest - I don't really know but I would be surprised and
dissapointed
> if they
> didn't because they definitely keep the size and can access it with an
> inline method
> making the potential saving over a function call compartively large.
So I looked in the standard. 21.3.7.2 says operator== where one argument is
a const charT* uses traits::length(). And my implementation is
template <class _CharT, class _Traits, class _Alloc> inline bool _STLP_CALL
operator==(const _CharT* __s,
const basic_string<_CharT,_Traits,_Alloc>& __y) {
_STLP_FIX_LITERAL_BUG(__s)
size_t __n = _Traits::length(__s);
return __n == __y.size() && _Traits::compare(__s, __y.data(), __n) == 0;
}
Strange to me. Looking in class std::char_traits it appears there is no
compare function taking 2 arguments, namely const char_type * and const
char_type *. There is only one compare function taking 3 arguments, namely
const char_type * and const char_type * and a size_t representing the number
of elements to compare.
Strange, I think lots of people use string=="this" or string=="that" -- and
lots of my own code has it. Yet calling strcmp seems it would be more
efficient!
So it means the OP's version #2 is efficient, apart from your version #5!
Comparing apples and oranges. All operator== has to do is determine
if the strings are identical or not. But strcmp() has to return which
one comes first in a lexicographical ordering in the current locale.
For strcmp() there is little option but to iterate char-by-char over the
string, and when a direct compare is different, then call a lexicographical
compare function, and check for reaching \0, etc.
operator== implementations can bypass all this slowness
and do a length check followed by a memcmp (both fast operations).
Finally, IMHO the type-safety of #1 [comparing std::strings with ==]
outweighs all of these other considerations.
But std::string's operator== cannot "just call strcmp", because a std::string
may contain embedded \0 characters (a capabillity you may or may not consider
terrible useful, but it's required by the standard), and strcmp would only
compare the strings up to the first \0 in one of the strings, e.g "abc\0def"
would compare equal to "abc\0xyz" when using strcmp.
Oh dear - I forgot about the embedded nulls because one of the arguments
doesn't have them.
When you compare two things of different types you have to change one top
the type of the other:
If you 'promote' the char* to string then you cannot strcmp.
If you 'promote' the string to a char* then you can use strcmp.
Unfortunately the std implies (but does not actually state) the first case.
I would have hoped that this was such common practice that the std would
explicitly require strcmp semantics for efficiency.
>
> Strange, I think lots of people use string=="this" or string=="that" --
and
> lots of my own code has it. Yet calling strcmp seems it would be more
> efficient!
Yes because we know that our app will have already gauranteed no embedded
nulls.
>
> So it means the OP's version #2 is efficient, apart from your version #5!
>
>
Thank goodness string isn't localized otherwise it couldn't even use memcmp.
I got quite worried there but I checked the std and it says that
char_traits<char> is specialized in such
a way that memcmp can be used.