C++比较两个字符串字面值

5

当使用==运算符(或者!=)比较一个字符串字面值和另一个字符串字面值时,结果是否是良好定义的?

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

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

请不要说像“使用std::string”这样的东西,我只想知道这个特定情况。

为什么你需要这样做?为了保证返回 false,尝试使用 assert(!"消息内容在这里"); - chris
1
@chris:一方面是出于好奇心,另一方面是为了实现类似枚举的类。 - Thomas Eding
1
实现定义,据我所知; as == 比较 const char* S 的地址。 - manasij7479
2个回答

15
"a" == "a"

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

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

"a" != "b"

这个表达式必须返回false,因为这两个字符串字面值不可能占用同一内存位置:"a"[0] != "b"[0]


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

由于我们正在比较指针,因此关系比较运算符(<><=>=)比相等性比较运算符(==!=)更具问题性,因为只有一组受限制的指针比较可以使用关系比较运算符进行。只有两个指针都指向同一个数组或同一对象时,它们才能进行关系比较。

如果两个字符串字面值"a"在内存中占据相同位置,则"a" < "a"将是完全定义的并返回false,因为两个指针均指向同一数组的初始元素('a')。

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

由于"a""b"永远不可能占用同一内存位置,"a" < "b"始终具有未定义行为。其他关系比较运算符也是如此。

如果出于某种原因,您想要对两个字符串字面值进行关系比较,并且需要定义良好的结果,则可以使用std::less比较器,它在所有指针上提供了严格弱排序。虽然相同内容的字符串字面值可能不相等,但我不知道为什么会有人这样做,但您可以这样做。


我认为如果您也能讨论一下不太明确的小于比较和std::less及其相关内容,那就太好了。 - Cheers and hth. - Alf
@Cheersandhth.-Alf: 好主意,已添加。另外,我不知道是否提到过,但我喜欢你如何将“Cheers and hth”纳入你的名字中,以避免更加脾气暴躁的Stack Overflow贡献者。;-) - James McNellis

1
在C++中,字符串字面量是数组。由于数组没有为它们定义比较运算符,因此使用最佳匹配进行比较 - 指针比较运算符,因为数组将隐式衰减为指针,所以任何比较都会比较地址而不是内容。由于"a"和"b"不能在同一内存位置,"a"!="b"是一个真实的断言。它也形成了一个有效的静态断言。关于"a"=="a",没有这样的保证,但是GCC使用-fmerge-constants(在-O1时隐含)可以产生相当强的概率,而-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(或gcc>= 4.7的-std=c++11)进行编译,然后...

error: static assertion failed: "strings are not equal"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接