2012-06-21 2 views
5

При сравнении строкового литерала с другим строковым литералом с оператором == (или !=), является ли результат корректным?C++ сравнение двух строковых литералов

Например, гарантируется сохранение следующих условий?

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

Пожалуйста, не говорите, например, как «использовать std :: string». Я просто хочу знать этот конкретный случай.

+0

Зачем вам это нужно? Для гарантированного false попробуйте 'assert (!" Message here here ");' – chris

+1

@chris: Любопытство для одного. Также для идеи реализации типа перечислимого типа. –

+0

Возможный дубликат [Выходная разница в gcc и turbo C] (http://stackoverflow.com/questions/3289354/output-difference-in-gcc-and-turbo-c) – kennytm

ответ

15
"a" == "a" 

Это выражение может дать true или false; нет никаких гарантий. Два строковых литерала "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_equal, и std::less_equal Сравнить цены.Учитывая, что строковые литералы с одним и тем же содержимым могут не сравниться с равными, я не знаю, почему это когда-либо хотелось бы сделать, но вы можете.

+0

Я думаю, было бы неплохо, если бы вы могли обсуждать менее, чем сравнения, которые менее четко определены, и 'std :: øess' & friends –

+0

@ Cheersandhth.-Alf: Хорошая идея; добавлено. Кроме того, я не знаю, упомянул ли я об этом, но мне нравится, как вы включили «Приветствия и hth» в свое имя, чтобы обойти более суровых вкладчиков Stack Overflow. ;-) –

1

Идея заключается в том, что в C++ строковые литералы представляют собой массивы. Поскольку у массивов нет операторов сравнения, определенных для них, они сравниваются с использованием следующего наилучшего соответствия - оператора сравнения указателей, поскольку массивы будут неявно распадаться на указатели, поэтому любое сравнение сравнивает адрес, а не контент. Поскольку «a» и «b» не могут находиться в одном и том же месте памяти, «a»! = «B» является истинным утверждением. Он также формирует действительное статическое утверждение. Никакая такая гарантия не может быть сделана в отношении «a» == «a», хотя GCC с -fmerge-константами (подразумевается при -O1) может иметь достаточно сильную вероятность, а все-константы -fmerge могут дать вам гарантию (что потенциально приводит к несоответствующему поведению).

Если вам требуется сравнение на основе контента, вы всегда можете использовать assert(!strcmp("a", "a")). Или, вы можете использовать какой-STRCMP основе constexpr для статического утверждения:

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" 
Смежные вопросы