web-dev-qa-db-ja.com

文字列リテラルのC ++比較

私はc ++初心者です(ちょうどオールドスクール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を出力しますが、連続して実行すると、異なる答えが得られますか?

62
simusid

メモリアドレスを比較しています。どうやらあなたのコンパイラは文字列リテラルをそれらに遭遇した順序でメモリに配置するので、最初のものは2番目のものより「少ない」です。

最初のスニペットでは、最初に「A」、次に「Z」が表示されるため、「A」は小さくなります。 2番目に最初に「Z」が表示されるため、「Z」は小さくなります。最後のスニペットでは、2番目のコマンドがロールアラウンドするときに、リテラル「A」と「Z」がすでに配置されています。

86
Wintermute

文字列リテラルには静的な保存期間があります。これらすべての比較では、コンパイラによって文字列リテラルに割り当てられたメモリのアドレスが比較されます。コンパイラが最初に検出した文字列リテラルは、次に検出された文字列リテラルと比較して低いアドレスでメモリに格納されているようです。

したがって、このプログラムでは

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

文字列リテラル「Z」は、コンパイラによって最初に検出されたため、文字列リテラル「A」よりも低いアドレスで割り当てられました。

その比較を考慮に入れる

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

コンパイラは文字列リテラルに2つのエクステントのメモリを割り当てるか、同じ文字列リテラルのコピーを1つだけ使用する可能性があるため、コンパイラのオプションに応じて異なる結果が得られる可能性があります。

C++標準から(2.14.5文字列リテラル)

12すべての文字列リテラルが異なる(つまり、重複しないオブジェクトに格納される)かどうかは、実装によって定義されます。文字列リテラルを変更しようとした場合の影響は定義されていません。

同じことがCにも当てはまります。

20

声明の中で:

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

2 文字列リテラル"A"および"Z"を作成しました。これらはタイプconst char *であり、これはnullで終了する文字配列へのポインターです。ここでの比較は、ポインターが指す値ではなく、ポインターを比較することです。ここでのメモリアドレスの比較が、コンパイラに警告を与えるものです。比較の結果は、コンパイラがメモリをどこに割り当てたかによって決まります。メモリは、コンパイラごとにいくらか任意になります。この場合、最初に見つかったリテラルは、コンパイラによって最初のメモリアドレスが割り当てられているように見えます。

Cの場合と同様に、これらの文字列リテラルを適切に比較するには、値の比較を行う strcmp を使用する必要があります。

ただし、次のようにして、より慣用的なc ++の方法で何かを行う場合。

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

次に、その比較演算子がstd::stringに対して定義されているため、値の適切な比較が行われます。

14
shuttle87

C++では、結果は指定されていません。 C++ 11には N3337 を使用します。

まず、文字列リテラルのタイプを確認する必要があります。

§2.14.5

9通常の文字列リテラルおよびUTF-8文字列リテラルは、ナロー文字列リテラルとも呼ばれます。狭い文字列リテラルのタイプは「arrayofnconst char」です。ここで、nは、以下に定義されている文字列のサイズであり、静的ストレージ期間(3.7)があります。

配列は口語的にポインターへの減衰と言われます。

§4.2

1タイプ「arrayofN T」または「arrayofunknown bound of T」の左辺値または右辺値は、タイプ「pointertoT」のprvalueに変換できます。結果は、配列の最初の要素へのポインターです。

文字列リテラルには両方とも1文字が含まれているため、それらは同じタイプです(char[2]、ヌル文字を含む)。

したがって、次の段落が適用されます。

§5.9

2 [...]

同じタイプのオブジェクトまたは関数へのポインター(ポインター変換後)を比較すると、結果は次のように定義されます。

[...]

—同じタイプの2つのポインタpqが、同じオブジェクトまたは同じ配列の要素のメンバーではない異なるオブジェクト、または異なる関数を指している場合、またはそれらの1つだけがnullの場合、p<qp>qp<=q、およびp>=qは指定されていません。

不特定とは、動作が実装に依存することを意味します。 GCCがこれについて警告を出していることがわかります。

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

動作mayは、コンパイラーまたはコンパイラー設定によって変わる可能性がありますが、実際には、Wintermuteの answer を参照してください。

7
user3920237

実際のC++文字列を比較する場合は、C++文字列を宣言する必要があります。

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

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

文字列は、メモリ領域へのポインタを表しています。したがって、最初はメモリアドレスのみをそのようなコードと比較します

"Z"< "A"

文字列の比較は関数を使用して行われます。それらはあなたが持っている「どんな種類の弦」に依存します。 char配列文字列がありますが、それらはオブジェクトでもあります。これらのオブジェクトには、他の比較機能があります。たとえば、MFCのCStringには、Compareだけでなく、CompareNoCase関数もあります。

文字列には、strcmpを使用するのが最適です。デバッグしてステップインすると、関数の機能がわかります。両方の文字列のすべての文字を比較し、最初の違いが発生した場合は整数を返し、同じ場合はゼロを返します。

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

ここでさらにいくつか見つける サンプルコード

0
Karsten

C++の文字列定数(「A」および「Z」)は、Cの概念(最後の文字が「\ 0」である文字の配列)によって表されます。このような定数は、strcmp()タイプの関数と比較する必要があります。

C++ std :: string比較を使用する場合は、次のように明示的に指定する必要があります。

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

メモリアドレスを比較しています。次の例では、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;
}
0