2012-06-21 326 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"