2012-06-21 225 views
5

将字符串文字与另一个字符串文字与==运算符(或!=)进行比较时,结果是否定义良好?C++比较两个字符串文字

例如,下面是否有保证?

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

请不要说像“使用std :: string”的东西来代替。我只想知道这个具体案例。

+0

为什么你需要这样做?对于保证为假的,尝试'assert(!“Message goes here”);' – chris

+1

@chris:好奇之一。也适用于枚举类实现的想法。 –

+0

[gcc和turbo C中的输出差异]的可能的重复(http://stackoverflow.com/questions/3289354/output-difference-in-gcc-and-turbo-c) – kennytm

回答

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::greater,std::greater_equalstd::less_equal比较器。考虑到具有相同内容的字符串文字可能不会相等,我不知道为什么要这样做,但你可以。

+0

我认为如果你还可以讨论比较不那么明确的比较,以及'std ::øess'&friends –

+0

@ Cheersandhth.-Alf:好主意;添加。另外,我不知道我是否已经提到过这个问题,但我喜欢你如何在名称中加入“Cheers and hth”来解决更加恶意的Stack Overflow贡献者。 ;-) –

1

这个想法是,在C++字符串文字是数组。由于数组没有为它们定义比较运算符,因此它们会使用下一个最佳拟合 - 指针比较运算符进行比较,因为数组会隐式衰减指针,所以任何比较都会比较地址而不是内容。由于“a”和“b”不能位于相同的存储位置,因此“a”!=“b”是一个真正的断言。它也形成一个有效的静态断言。尽管具有-fmerge常量(暗示在-O1处)的GCC可以提供相当强的概率,并且所有常量都可以为您提供保证,但是对于“a”==“a”没有这样的保证。导致不符合的行为)。

如果您碰巧想要进行基于内容的比较,则始终可以使用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... 

然后,用克编译++ -std =的C++ 0x(或-std = C++ 11 GCC> = 4.7) ,...

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