5

==使用运算符(或)将字符串文字与另一个字符串文字进行比较时!=,结果是否定义明确?

例如,以下是否保证成立?

assert("a" == "a");
assert("a" != "b");

请不要说“使用 std::string”之类的东西。我只是想知道这个具体案例。

4

2 回答 2

15
"a" == "a"

这个表达式可能产生trueor false; 没有任何保证。这两个"a"字符串文字可能占用相同的存储空间,也可能存在于内存中的两个不同位置。

我认为 C++ 标准中最接近的语言是:“是否所有字符串文字都是不同的(即,是否存储在不重叠的对象中)是实现定义的”(C++11 §2.14.5/12)。没有其他要求或限制,因此未指定结果。

"a" != "b"

这个表达式必须屈服false,因为这两个字符串文字不可能占据内存中的相同位置: "a"[0] != "b"[0].


当您以这种方式比较字符串文字时,您实际上是在比较指向数组中初始元素的指针。

因为我们正在比较指针,所以关系比较(<><=>=)比相等比较(==!=)更成问题,因为使用关系比较只能执行一组受限的指针比较。如果两个指针都是指向同一数组的指针或指向同一对象的指针,则只能进行关系比较。

如果两个"a"字符串字面量在内存中占据相同的位置,那么"a" < "a"将是明确定义的并且会 yield false,因为两个指针都指向'a'同一个数组的初始元素 ( )。

但是,如果两个"a"字符串字面量在内存中占据不同"a" < "a"的位置,则结果是不确定的,因为被比较的两个指针指向完全​​不相关的对象。

因为"a"and"b"永远不能在内存中占据相同的位置,所以"a" < "b"总是有未定义的行为。其他关系比较运算符也是如此。

如果您出于某种原因想要对两个字符串文字进行关系比较并获得明确定义的结果,则可以使用std::less比较器,它为所有指针提供严格-弱排序。还有std::greater, std::greater_equal, 和std::less_equal比较器。鉴于具有相同内容的字符串文字可能比较不相等,我不知道为什么有人会想要这样做,但你可以。

于 2012-06-21T18:08:18.613 回答
1

这个想法是在 C++ 中字符串文字是数组。由于数组没有为它们定义比较运算符,因此使用下一个最佳拟合比较它们 - 指针比较运算符,因为数组将隐式衰减为指针,因此任何比较都比较地址而不是内容。由于 "a" 和 "b" 不能位于同一内存位置,因此 "a" != "b" 是一个真正的断言。它还形成一个有效的静态断言。不能对“a”==“a”做出这样的保证,尽管带有 -fmerge-constants(隐含在 -O1 处)的 GCC 可以产生相当强的概率,并且 -fmerge-all-constants 可以给你一个保证(可能导致不合格行为)。

如果您碰巧想要基于内容的比较,您始终可以使用assert(!strcmp("a", "a")). 或者,您可以将某种基于 constexpr 的 strcmp 用于静态断言:

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...

然后,使用 g++ -std=c++0x (或 -std=c++11 用于 gcc >= 4.7)进行编译,然后...

error: static assertion failed: "strings are not equal"
于 2012-06-21T18:33:39.807 回答