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

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

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

напечатает 1

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

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

int main() 
{ 
  cout << ("Z"< "A");
  cout << ("A"< "Z");
}
будет печатать 10. Индивидуально оба оператора cout печатают 1, но выполняются подряд, я получаю другой ответ?

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 что будет делать сравнения стоимости.

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

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 также называется узкими строковыми литералами. Узкий строковый литерал имеет тип "массив n const char", где n размер строки как определено ниже, и имеет статическую длительность хранения (3.7).

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

§4.2

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

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

поэтому применяется следующий абзац:

§5.9

2 [...]

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

[...]

- если два указателя p и q одного и того же типа указывают на разные объекты, не являющиеся членами одного и того же объекта или элементов тот же массив или для разных функций, или если только одна из них равна null, результаты 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 - массивом символов, где последний символ "\0". Такие константы должны сравниваться с типом функции strcmp ().

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

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

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

"Z"< "A"

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

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

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

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