15

たとえば"hello"、タイプがconst char*. だから私の質問は:

  1. "hello"次のように、リテラル文字列 likeを non -like に割り当てるにはどうすればよいconst char*ですか。

    char* s = "hello";  // "hello" is type of const char* and s is char*
                        // and we know that conversion from const char* to
                        // char* is invalid
    
  2. すべてのプログラムでメモリを消費するのようなリテラル文字列"hello"ですか、それともステートメントの終了時に破棄される一時変数のようなものですか?

4

5 に答える 5

24

実際、"hello"タイプはchar const[6]です。

しかし、質問の要点は依然として正しいです。なぜ C++ では、読み取り専用のメモリ位置を非const型に割り当てることができるのでしょうか?

これの唯一の理由は、知らなかった古い C コードとの下位互換性constです。ここで C++ が厳密であった場合、多くの既存のコードが壊れていたでしょう。

とはいえ、ほとんどのコンパイラは、非推奨のコードについて警告するように構成できます。また、デフォルトでそうするように構成することもできます。さらに、C++11 はこれを完全に禁止していますが、コンパイラはまだ強制していない可能性があります。


標準ファン向け:
[参照 1] C++03 標準: §4.2/2

ワイド文字列リテラルではない文字列リテラル (2.13.4) は、「char へのポインタ」型の右辺値に変換できます。ワイド文字列リテラルは、「wchar_t へのポインター」型の右辺値に変換できます。いずれの場合も、結果は配列の最初の要素へのポインターです。この変換は、明示的な適切なポインター ターゲット型がある場合にのみ考慮され、左辺値から右辺値に変換する必要がある場合は考慮されません。[注: この変換は非推奨です. 附属書 D を参照。【例:「abc」は、配列からポインタへの変換で「const charへのポインタ」に変換され、修飾変換で「charへのポインタ」に変換されます。]

C++11 では、C++11 では違法なコードであることを意味する上記の引用を単純に削除しています。

[参照 2] C99 標準 6.4.5/5「文字列リテラル - セマンティクス」:

変換フェーズ 7 では、値ゼロのバイトまたはコードが、文字列リテラルまたはリテラルから生じる各マルチバイト文字シーケンスに追加されます。次に、マルチバイト文字シーケンスを使用して、シーケンスを格納するのに十分な長さの静的ストレージ期間の配列を初期化します。文字列リテラルの場合、配列要素は char 型を持ち、マルチバイト文字シーケンスの個々のバイトで初期化されます。ワイド文字列リテラルの場合、配列要素は wchar_t 型を持ち、ワイド文字のシーケンスで初期化されます...

これらの配列の要素が適切な値を持っている場合、これらの配列が異なるかどうかは指定されていません。プログラムがそのような配列を変更しようとした場合、動作は未定義です。

于 2012-04-22T14:19:20.810 に答える
2

「hello」のようなリテラル文字列は、すべてのプログラムでメモリを使用します。これは、ステートメントの終了時に破棄される一時変数のようなものです。

これはプログラムデータに保持されるため、プログラムの存続期間内に使用できます。現在のスコープからこのデータへのポインタと参照を返すことができます。

const char*キャストされる唯一の理由はchar*、winapiシステムコールのように、cとの互換性です。そして、このキャストは、他のconstキャストとは異なり、明示的ではありません。

于 2012-04-22T14:27:13.010 に答える
1

2 番目の質問に対する答えは、変数sが RAM にポインタから文字への型として格納されていることです。グローバルまたは静的の場合、ヒープに割り当てられ、実行中のプログラムの存続期間中そこに残ります。ローカル (「自動」) 変数の場合、スタックに割り当てられ、現在の関数が戻るまでそこに残ります。いずれの場合も、ポインタを保持するために必要なメモリ量を占有します。

文字列"Hello"は定数であり、他のすべての定数および初期化子と共に、プログラム自体の一部として格納されます。アプライアンスで実行するようにプログラムを作成した場合、文字列は ROM に保存されます。

文字列は定数でありsポインタであるため、コピーは必要ありません。ポインターsは、文字列が格納されている場所を指すだけです。

于 2012-04-22T14:37:09.617 に答える
1

を使用するだけstringです:

std::string s("hello");

それがC++の方法です。本当に を使用するchar必要がある場合は、配列を作成してその内容をコピーする必要があります。

于 2012-04-22T14:19:31.277 に答える
-3

あなたの例では、割り当てではなく構築しています。たとえば、std::string にはstd::string(const char *)コンストラクターがあります (実際にはもっと複雑ですが、問題ではありません)。同様に、char * (型へのポインターではなく型の場合) は、メモリをコピーする const char * コンストラクターを持つことができます。

ここでコンパイラが実際にどのように機能するかは実際にはわかりませんが、上記で説明したものと似ていると思います。 のコピーが"Hello"スタックで構築されs、このコピーのアドレスで初期化されます。

于 2012-04-22T14:28:42.950 に答える