Reputation: 1
When comparing a string literal with another string literal with the ==
operator (or !=
), is the result well defined?
For example, are the following guaranteed to hold?
assert("a" == "a");
assert("a" != "b");
Please don't say stuff like "use std::string" instead. I just want to know this specific case.
Upvotes: 5
Views: 3521
Reputation: 4039
The idea is that in C++ string literals are arrays. Since arrays do not have comparison operators defined for them, they are compared using the next best fit - the pointer comparison operator, as arrays will implicitly decay to pointers, so any comparison compares address and not content. Since "a" and "b" cannot be at the same memory location, "a" != "b" is a true assertion. It also forms a valid static assertion. No such guarantee can be made about "a" == "a", though GCC with -fmerge-constants (implied at -O1) can make a reasonably strong probability and -fmerge-all-constants can give you a guarantee (that potentially results in non-conforming behavior).
If you happen to want a content-based comparison, you can always use assert(!strcmp("a", "a"))
. Or, you can use some sort of constexpr based strcmp for a static assertion:
constexpr bool static_strequal_helper(const char * a, const char * b, unsigned len) {
return (len == 0) ? true : ((*a == *b) ? static_strequal_helper(a + 1, b + 1, len - 1) : false);
}
template <unsigned N1, unsigned N2>
constexpr bool static_strequal(const char (&str1)[N1], const char (&str2)[N2]) {
return (N1 == N2) ? static_strequal_helper(&(str1[0]), &(str2[0]), N1) : false;
}
static_assert(static_strequal("asdf", "asdf"), "no error - strings are equal");
static_assert(static_strequal("asdf", "jkl;"), "strings are not equal");
assert(!strcmp("asdf", "jkl;")); //no compile error - runtime error
//cannot use strcmp in static assert as strcmp is not constexpr...
Then, compile with g++ -std=c++0x (or -std=c++11 for gcc >= 4.7), and...
error: static assertion failed: "strings are not equal"
Upvotes: 1
Reputation: 355177
"a" == "a"
This expression may yield true
or false
; there are no guarantees. The two "a"
string literals may occupy the same storage or they may exist at two different locations in memory.
I think that the closest language in the C++ Standard is: "Whether all string literals are distinct (that is, are stored in nonoverlapping objects) is implementation defined" (C++11 §2.14.5/12). There are no other requirements or restrictions, so the result is left unspecified.
"a" != "b"
This expression must yield false
because there is no way that these two string literals can occupy the same location in memory: "a"[0] != "b"[0]
.
When you compare string literals in this way, you are really comparing the pointers to the initial elements in the arrays.
Because we are comparing pointers, the relational comparisons (<
, >
, <=
, and >=
) are even more problematic than the equality comparisons (==
and !=
) because only a restricted set of pointer comparisons may be performed using the relational comparisons. Two pointers may only be relationally compared if they are both pointers into the same array or pointers into the same object.
If the two "a"
string literals occupy the same location in memory, then "a" < "a"
would be well-defined and would yield false
, because both pointers point to the initial element ('a'
) of the same array.
However, if the two "a"
string literals occupy different locations in memory, the result of "a" < "a"
is undefined, because the two pointers being compared point into entirely unrelated objects.
Because "a"
and "b"
can never occupy the same location in memory, "a" < "b"
always has undefined behavior. The same is true for the other relational comparison operators.
If you did, for some reason, want to relationally compare two string literals and have well-defined results, you can use the std::less
comparer, which provides a strict-weak ordering over all pointers. There are also std::greater
, std::greater_equal
, and std::less_equal
comparers. Given that string literals with the same contents may not compare equal, I don't know why one would ever want to do this, but you can.
Upvotes: 15