C++ сравнение строковых литералов


Я новичок в c++ (просто oldschool c). Мой сын попросил помочь с этим и я не могу это объяснить. Если бы он спросил меня "как мне сравнить строки", Я бы сказал ему использовать strcmp (), но это не то, что меня смущает. Вот что он спросил:

int main() 
{ 
  cout << ("A"< "Z");
}

напечатает 1

int main() 
{ 
  cout << ("Z"< "A");
}

также будет печатать 1, но

int main() 
{ 
  cout << ("Z"< "A");
  cout << ("A"< "Z");
}

затем напечатает 10. По отдельности оба оператора cout печатают 1, но выполняются подряд я получаю другой ответ?

8 60

8 ответов:

вы сравниваете адреса памяти. По-видимому, ваш компилятор помещает строковые литералы в память в том порядке, в котором он их встречает, поэтому первый "меньше", чем второй.

поскольку в первом фрагменте он видит" A "первым и" Z "вторым," A " меньше. Поскольку он видит "Z" сначала во втором, "Z" меньше. В последнем фрагменте он уже имеет литералы "A" и "Z", размещенные при выполнении второй команды.

строковые литералы имеют статическую длительность хранения. Во всех этих сравнениях сравниваются адреса памяти, выделенные компилятором для строковых литералов. Кажется, что первый строковый литерал, с которым сталкивается компилятор, хранится в памяти с более низким адресом по сравнению со следующим встреченным строковым литералом.

таким образом в этой программе

int main() 
{ 
  cout << ("Z"< "A");
  cout << ("A"< "Z");
}

строковый литерал "Z" был alllocated с более низким адресом, чем строковый литерал "A", потому что он был найден сначала компилятором.

примите во внимание это сравнение

  cout << ("A"< "A");

может давать разные результаты в зависимости от параметров компилятора, поскольку компилятор может либо выделить два экстента памяти для строковых литералов, либо использовать только одну копию строковых литералов, которые являются одинаковыми.

из стандарта C++ (2.14.5 строковые литералы)

12 являются ли все строковые литералы различными (то есть хранятся в неперекрывающийся объекты) определяется реализация. Влияние попытка изменить строковый литерал не определена.

то же самое справедливо и для C.

в заявлении:

cout << ("A"< "Z");

вы создали 2 строковые литералы:"A" и "Z". Они относятся к типу const char * который является указателем на нулевой завершенный массив символов. Сравнение здесь заключается в сравнении указателей, а не значений, на которые они указывают. Это сравнение адресов памяти, что дает вам предупреждение компилятора. Результат сравнения будет определяться тем, где компилятор выделил память который будет несколько произвольным от компилятора к компилятору. В этом случае похоже, что первый найденный литерал получает первый адрес памяти вашим компилятором.

так же, как в C, чтобы сравнить эти строковые литералы правильно, вам нужно использовать strcmp который будет делать сравнение значений.

однако, когда вы делаете что-то более идиоматические с++ так делать:

cout << (std::string("A") < std::string("Z"));

тогда вы получите правильное сравнение значений, как этот оператор сравнения определен для std::string.

Если вы хотите сравнить фактические строки C++, вам нужно объявить строки C++:

int main() 
{
  const std::string a("A");
  const std::string z("Z");

  cout << (z < a) << endl; // false
  cout << (a < z) << endl; // true
}

в C++ результаты не указаны. Я буду использовать N3337 для C++11.

во-первых, мы должны посмотреть, что такое тип строкового литерала.

§2.14.5

9 обычные строковые литералы и строковые литералы UTF-8 также являются называется узкими строковыми литералами. Узкий строковый литерал имеет тип "массив nconst char", где n - это размер строки как определено ниже, и имеет статическую длительность хранения (3.7).

массивы в разговорной речи говорят распад указатели.

§4.2

1 значение lvalue или rvalue типа " массив N T" или "массив неизвестного граница T "может быть преобразован в prvalue типа" указатель на T". Результатом является указатель на первый элемент массива.

так как ваши строковые литералы содержат один символ, они одного типа (char[2], включая нулевой символ.)

поэтому применяется следующий пункт:

§5.9

2 [...]

указатели на объекты или функции одного типа (после указателя преобразования) можно сравнить с результатом, определенным следующим образом:

[...]

- если два указателя p и q одного и того же типа указывают на разные объекты, которые не являются членами одного и того же объекта или элементов один и тот же массив или для разных функций, или если только одна из них равна нулю, результаты p<q,p>q,p<=q и p>=q не определен.

Unspecified означает, что поведение зависит от реализации. Мы видим, что GCC дает предупреждение об этом:

warning: comparison with string literal results in unspecified behaviour [-Waddress]
     std::cout << ("Z" < "A");

поведение мая изменение между компиляторами или настройками компилятора, но в практика для того, что происходит, см. Wintermute в ответ.

вы сравниваете адреса памяти. В следующем примере объясняется, как сравнить 2 строки:

#include "stdafx.h"
#include <iostream>
#include <cstring> //prototype for strcmp()

int _tmain(int argc, _TCHAR* argv[])
{
 using namespace std;

 cout << strcmp("A", "Z"); // will print -1
 cout << strcmp("Z", "A"); // will print 1

 return 0;
}

строковые константы ("A "и" Z") В C++ представлены C concept - массивом символов, где последний символ - '\0'. Такие константы должны сравниваться с типом функции strcmp ().

Если вы хотите использовать сравнение c++ std::string, вы должны явно указать его:

cout << (std::string( "A") < "Z");

строка представляет собой указатель на область памяти. Так что вы сначала сравните только адреса памяти с таким кодом

"Z"< "A"

сравнение строк выполняется с функциями. Они зависят от того," какая строка " у вас есть. У вас есть строки массива символов, но они также являются объектами. Эти объекты имеют другие функции сравнения. Например, CString в MFC имеет функцию Compare, но также и функцию CompareNoCase.

для ваших строк лучше всего использовать strcmp. Если вы отладка и шаг в вы видите, что делает функция: она сравнивает каждый символ обеих строк и возвращает целое число, если происходит первое различие или ноль, если то же самое.

int result = strcmp("Z", "A");

здесь вы найдете некоторые дополнительные пример кода