2012-06-21 94 views
5

Khi so sánh chuỗi ký tự bằng một chuỗi ký tự khác với toán tử == (hoặc !=), kết quả được xác định rõ chưa?C++ so sánh hai chuỗi ký tự

Ví dụ: những điều sau được bảo đảm giữ?

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

Xin đừng nói những thứ như "sử dụng std :: string" thay thế. Tôi chỉ muốn biết trường hợp cụ thể này.

+0

Tại sao bạn cần thực hiện việc này? Đối với một giả mạo được bảo đảm, hãy thử 'assert (!" Message go here "); ' – chris

+1

@chris: Sự tò mò cho một. Cũng cho một ý tưởng thực hiện lớp giống như enum. –

+0

có thể trùng lặp của [Chênh lệch đầu ra trong gcc và turbo C] (http://stackoverflow.com/questions/3289354/output-difference-in-gcc-and-turbo-c) – kennytm

Trả lời

15
"a" == "a" 

biểu hiện này có thể mang lại true hoặc false; không có bảo đảm. Hai ký tự chuỗi "a" có thể chiếm cùng một bộ nhớ hoặc chúng có thể tồn tại ở hai vị trí khác nhau trong bộ nhớ.

Tôi nghĩ rằng ngôn ngữ gần nhất trong C++ Standard là: "Cho dù tất cả các chuỗi ký tự là khác biệt (nghĩa là, được lưu trữ trong các đối tượng nonoverlapping) được thực hiện xác định" (C++ 11 §2.14.5/12). Không có yêu cầu hoặc hạn chế nào khác, do đó kết quả không được chỉ định.

"a" != "b" 

biểu này phải nhường false vì không có cách nào mà hai xâu có thể chiếm cùng một vị trí trong bộ nhớ: "a"[0] != "b"[0].


Khi bạn so sánh xâu theo cách này, bạn đang thực sự so sánh các con trỏ đến các yếu tố ban đầu trong mảng.

Bởi vì chúng ta đang so sánh con trỏ, so sánh quan hệ (<, >, <=, và >=) thậm chí còn nhiều vấn đề hơn so sánh bình đẳng (==!=) bởi vì chỉ có một tập hạn chế so sánh con trỏ có thể được thực hiện bằng cách sử dụng quan hệ so sánh. Hai con trỏ chỉ có thể được so sánh theo quan hệ nếu chúng là cả hai con trỏ vào cùng một mảng hoặc con trỏ vào cùng một đối tượng.

Nếu hai "a" xâu chiếm cùng một vị trí trong bộ nhớ, sau đó "a" < "a" sẽ được xác định rõ và sẽ mang lại false, bởi vì cả hai con trỏ trỏ đến các yếu tố ban đầu ('a') của cùng một mảng.

Tuy nhiên, nếu hai "a" xâu chiếm địa điểm khác nhau trong bộ nhớ, kết quả của "a" < "a" là undefined, vì hai con trỏ được điểm thành các đối tượng hoàn toàn không liên quan so sánh.

"a""b" không bao giờ có thể chiếm cùng một vị trí trong bộ nhớ, "a" < "b" luôn có hành vi không xác định. Điều này cũng đúng đối với các toán tử so sánh quan hệ khác. Nếu bạn đã làm, vì một lý do nào đó, muốn so sánh hai chuỗi ký tự và có kết quả được xác định rõ, bạn có thể sử dụng trình so sánh std::less, cung cấp thứ tự khắt khe trên tất cả các con trỏ. Ngoài ra còn có std::greater, std::greater_equalstd::less_equal so sánh.Cho rằng các chuỗi ký tự có cùng nội dung có thể không so sánh bằng nhau, tôi không biết tại sao người ta lại muốn làm điều này, nhưng bạn có thể.

+0

Tôi nghĩ rằng nó sẽ là tốt đẹp nếu bạn cũng có thể thảo luận ít hơn so sánh, được ít được xác định, và 'std :: øess' & bạn bè –

+0

@ Cheersandhth.-Alf: ý tưởng tốt; thêm. Ngoài ra, tôi không biết nếu tôi đã đề cập đến điều này, nhưng tôi thích cách bạn đã kết hợp "Chúc mừng và hth" vào tên của bạn để làm việc xung quanh những người đóng góp Stack Overflow gắt gỏng hơn. ;-) –

1

Ý tưởng là trong chuỗi ký tự chuỗi C++ là mảng. Vì các mảng không có toán tử so sánh được xác định cho chúng, nên chúng được so sánh bằng cách sử dụng toán tử so sánh tốt nhất tiếp theo, vì mảng sẽ ngầm phân rã thành con trỏ, vì vậy bất kỳ so sánh nào so sánh địa chỉ và không nội dung. Vì "a" và "b" không thể ở cùng vị trí bộ nhớ, "a"! = "B" là xác nhận đúng. Nó cũng tạo thành một xác nhận tĩnh hợp lệ. Không bảo đảm như vậy có thể được thực hiện về "a" == "a", mặc dù GCC với các hằng số -fmerge (ngụ ý tại -O1) có thể tạo ra xác suất hợp lý và -fmerge-all-constants có thể cung cấp cho bạn bảo đảm (có khả năng kết quả trong hành vi không phù hợp).

Nếu bạn tình cờ muốn so sánh dựa trên nội dung, bạn luôn có thể sử dụng assert(!strcmp("a", "a")). Hoặc, bạn có thể sử dụng một số loại constexpr strcmp dựa cho một sự khẳng định tĩnh:

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

Sau đó, biên dịch với g ++ -std = C++ 0x (hoặc -std = C++ 11 cho gcc> = 4,7) , và ...

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