开发者

Test of equality using if statement in C++

This might be a stupid question to a experience programmer... but anyway, I just want to figure out. What's the difference between if("Hel开发者_如何学编程lo"==$helloString) and if(helloString=="Hello")? I thought the order in a if statement doesn't matter but I guess there must be something wrong with my thought. So could someone expalin it to me? Like in what kind of situation would one use the first/second if statement to do the test of equality? Thanks!!


It's a "safety" measure. If you have a typo, and leave out one of the '=' characters, you are doing assignment instead of comparison.

if (some_string = "Hello")

overwrites the string and the if is considered true (assuming using std::string). On the other hand:

if ("Hello" = somestring)

is a compilation error.

It looks a little weird, but it's considered a good, preventative coding measure in some circles.


What's wrong with your thought? I'll assume the random $ symbol is a typo. Both lines check if an object helloString is actually equal to the literal string "Hello". The ordering is a style preference - historically the constant was placed on the left hand side of the == to prevent accidental assignment (via =), though compilers now should warn of this behavior.

Do note that this would only work for objects of a type like std::string, which have overloaded == operators and would allow comparison such as this. This would not work if you were using C-style strings of char *.

#include <string>
#include <iostream>

int main()
{
    std::string helloString = "Hello";
    char *helloPtr = "Hello";

    if (helloString == "Hello") { std::cout << "Equal 1\n"; }
    if ("Hello" == helloString) { std::cout << "Equal 2\n"; }
    if (helloPtr == "Hello") // not a *wise* comparison because you are comparing pointers
    {

    }
}


as Tom mentions, You should be using strcmp or strncmp with strings. In other cases, some coding styles recommend putting the literal before the variable to avoid a common but sometimes difficult bug:

if (foo = 5)
{
    ...
}

The coder maybe meant foo == 5, which is true only if foo is equal to five, but instead has instructed the compiler to assign foo to five and do the if body every time. by following that literals first rule, the coder would have written:

if (5 = foo)
{
    ...
}

which is invalid, and won't compile, because 5 is not an l-value. The coder would have caught his mistake right away.

On the other hand, assignment in an if or while condition is actually a common idiom, and many C coders object to the literals first style because it's a little harder to read, for the same reason "If Angus is a Scotsman" scans more nicely than "If a Scotsman is Angus", even though both are technically equivalent.


Some compilers allow identifiers with $ symbols as a non-Standard extension... no big deal.

There are two aspects to this question - which you're interested in is not clear from the question:

  • the functionality is equivalent, in which case the choice of which to use is stylistic, and the less-oft-seen if("Hello" == helloString) is prefered by some programmers as it produces a compiler error if = is accidentally typed instead of ==
  • you're observing (or wondering if there's any chance of) functionality differing: the rest of this answer addresses this.

For operator==, users can provide their own comparison operators for classes/structs they define:

struct X
{
    // as a member function
    bool operator==(const char* rhs) const { return <some expression>; }
};

// as a non-member function (use this OR the member function)
bool operator==(const X& lhs, const char* rhs) { return <some expression>; }

// only possible as a non-member function, as X doesn't appear on the left of ==
bool operator==(const char* lhs, const X& rhs) { return <some expression>; }

You can also define equality between two Xs as a member of non-member function...

struct X
{
    bool operator(const X& rhs) const { return <some expression>; }
};

OR

bool operator==(const X& lhs, const X& rhs) { return <some expression>; }

But, these functions would only allow comparison against a string literal (your "Hello" is a string literal), if you tell the compiler it is allowed to implicitly create an X from a string literal by means of a suitable constructor:

struct X
{
    X(const char* p) /* initialiser list eg. */ : p_(p) { <option code> }
};

This would allow ("Hello"==helloString), if helloString is our X type, to be resolved as:

(X("Hello") == helloString)

Which - as above - you provide as member X::operator==(const X&) or non-member operator==(const X&, const X&).

Changing the constructor to be explicit prevents the compiler implicitly performing on-the-fly construction of Xs, which is typically best as implicit conversion can happen when not intended, and give make the intended resolution ambiguous or provide unwanted results.

struct X
{
    explicit X(const char* p) /* initialiser list eg. */ : p_(p) { <option code> }
};

Another way this expression can be evaluated for a user-defined type (class/struct), is to permit the compiler to create a type it already knows how to compare with a string literal from the user-defined type. The compiler knows how to compare two string literals but it doesn't do it in the way beginners expect - instead it compares the memory addresses at which the text is stored rather than the textual content stored at those addresses. This isn't normally useful to a beginner. For the record, a conversion operator looks like this:

struct X
{
    operator const char*() const { return <some expression>; }
};

This would be even less desirable than non-explicit constructors - they have the same issues re making some intended matches ambiguous, but can also provide the less useful string address comparison instead of string content comparison. Note that the C++ Standard's std::string provides a c_str() function that you must explicitly call when you want the address of the string content, and such an addresses may become invalid after any modification to the string (e.g. appending some more text).

Finally, if someString is NOT a class/struct, but is another string literal, then - as mentioned - the compiler will compare the addresses and not the string content. You can use the strcmp() function to compare the textual content:

if (strcmp("Hello", someString)) // compare textual content
    ...

This works if the string content doesn't embed any NUL (0) characters. Otherwise, a string class may provide a constructor from a pointer and data length (as std::string does), allowing:

if (X("Goodbye\000Cruel\000World", 19) == someString))
    ...


There is no $ operator in C++, therefore this statement is not valid:

if("Hello"==$helloString)


If one or the other is not defined. In the case of std::string, this is not the case. But it's possible to define a function like this:

bool operator==(X lhs, Y rhs);

Then you can call that function like this:

X x;
Y y;
if(x == y) {...}

But you can't do this:

if(y == x) {...}

Unless you define another function like this:

bool operator==(Y lhs, X rhs);


The order does not matter. However, you should only use the == operator if helloString is a std::string and not a C string. Additionally, there is no $ operator in C++, so you should omit that.

For example, if helloString is a C string (e.g. char *) use the strcmp function:


if(strcmp("Hello", other_str) == 0) {
   //  they are equal
} else {
   // they are not equal
}

Or if helloString is a std::string, it is acceptable to use the == operator:


if("Hello" == helloString) {
   //  they are equal
} else {
   // they are not equal
}

EDIT: I made numerous edits due to comments. Thanks y'all.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜