0

構文char * = "stringLiteral";を理解しています。は推奨されておらず、将来的には動作しなくなる可能性さえあります。私が理解していないのはWHYです。

私はネットとスタックを検索しましたが、char * = "stringLiteral"; であることを確認する多くのエコーがあります。const char * = "stringLiteral";は間違っています。は正しいですが、なぜ構文が間違っていると言ったのかについての情報をまだ見つけていません。言い換えれば、問題が実際にボンネットの下にあることを知りたいのです。

私の混乱を説明する

コード セグメント 1 - EVIL WAY (非推奨)

char* szA = "stringLiteralA";     //Works fine as expected. Auto null terminated.
std::cout << szA << std::endl;    
szA = "stringLiteralB";          //Works, so change by something same length OK.
std::cout << szA << std::endl;    
szA = "stringLiteralC_blahblah"; //Works, so change by something longer OK also.
std::cout << szA << std::endl;    

Ouput:
stringLiteralA
stringLiteralB
stringLiteralC_blahblah

では、ここでの問題は正確には何ですか?うまく機能しているようです。

コード セグメント 2 (「OK」の方法)

const char* szA = "stringLiteralA";  //Works fine as expected. Auto null term.
std::cout << szA << std::endl;    
szA = "stringLiteralB";          //Works, so change by something same length OK.
std::cout << szA << std::endl;    
szA = "stringLiteralC_blahblah"; //Works, so change by something longer OK also.
std::cout << szA << std::endl;    

Ouput:
stringLiteralA
stringLiteralB
stringLiteralC_blahblah

また、正常に動作します。変わりはない。const を追加するポイントは何ですか?

コード セグメント 3

const char* const szA = "stringLiteralA";  //Works. Auto null term.
std::cout << szA << std::endl;    
szA = "stringLiteralB";           //Breaks here. Can't reasign.

ここでは、可変コンテンツを読み取り専用で保護するには、 const char* const szA = "something";を実行する必要があることを示しているだけです。.

非推奨や問題のポイントがわかりません。この構文が廃止され、問題と見なされるのはなぜですか?

4

4 に答える 4

6

const char **定数 ( ) へのconstポインター( ) ですchar(ポインター定義は右から左に簡単に読み取れます)。ここでのポイントは、コンテンツを保護することです。標準が言うように、そのようなポインターのコンテンツを変更すると、未定義の動作が発生するためです。

これは、通常 (C/C++) コンパイラが、プログラム全体で使用される文字列を単一のメモリ ゾーンにグループ化し、プログラムの無関係な部分で使用される同じ文字列のインスタンスに対して同じメモリ位置を使用できるという事実に根ざしています。 (実行可能サイズ/メモリフットプリントを最小限に抑えるため)。文字列リテラルを変更することが許可されている場合、1 つの変更で同じリテラルの他の無関係なインスタンスに影響を与える可能性がありますが、これは明らかに優れたアイデアではありません。

実際、最近のほとんどのコンパイラ (メモリ保護をサポートするハードウェア上) では、文字列テーブルのメモリ領域は読み取り専用であるため、文字列リテラルを変更しようとすると、プログラムがクラッシュします。文字列リテラルを参照するポインターに追加constすると、これらの間違いがクラッシュではなくコンパイル エラーとしてすぐに明らかになります。

ところで、文字列リテラルが非 const に暗黙的に崩壊する可能性があるという事実は、上記のように、標準化前のライブラリ (まだ C 言語の一部ではなかっchar *たときに作成された) との下位互換性への譲歩にすぎないことに注意してください。const標準では、文字列リテラルの変更は UB であると常に述べられています。

于 2012-11-07T17:49:26.697 に答える
2

"abc"おそらく不変のメモリを指す静的配列です。Cでは、文字列リテラルの内容を変更することは未定義の動作 (UB) です。


"abc"しかし、C99 はtype のオブジェクトを作成しませんでしたconst char [n]。実際、これは (§3.1.4/3) を指定する C89 (および ANSI C) との互換性を維持するため、まったく逆です。

文字列リテラルは静的な保存期間とchar の型配列を持ち、指定された文字で初期化されます。

つまり、宣言

char* c = "12345";

Cでは、C11 までは非推奨ではありません。

http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdfから、C99 で文字列リテラルを UB に変更し、型を に維持する根拠を確認できますchar [n]

文字列リテラルは変更可能である必要はありません。この仕様により、実装は文字列のコピーを同一のテキストと共有し、文字列リテラルを読み取り専用メモリに配置し、特定の最適化を実行できます。ただし、文字列リテラルには、特にライブラリ関数でのポインタ型チェックの問題を回避するために、 const charの型配列がありません。文字列リテラルは変更可能であるべきだと主張した C89 委員会のメンバーは、このプラクティスを共通の拡張として指定することに満足していました (§J.5.5 を参照)。

ここで、C99 §J.5.5 は次のとおりです。

J.5.5 書き込み可能な文字列リテラル

文字列リテラルは変更可能です (この場合、同一の文字列リテラルは異なるオブジェクトを示す必要があります) (6.4.5)。


一方、コードは C++であるため、(C++03 §2.13.4/1) が必要なため、これは標準 C++ では実際には間違っているはずです。

... 通常の文字列リテラルは、型が「n const charの配列」であり、静的な保存期間があります ...

const char[n]aに aを割り当ててchar*もコンパイルされません。当時の既存の実装では変換が許可されていたため (C が許可しているため)、コンパイラは「非推奨」について警告し、付録 D: 互換性機能に移動しました。

D.4 const 文字列からの暗黙の変換

文字列リテラルの const から非 const 修飾への暗黙的な変換 (4.2) は非推奨です。

于 2012-11-07T17:44:31.620 に答える
2

非推奨の背後にある考え方は、実行時にクラッシュの原因となるエラーをコンパイラがキャッチできるようにすることです。

char *hello = "hello";
strcpy(hello, "world"); // Compiles but crashes

とは対照的に

const char *hello = "hello";
strcpy(hello, "world"); // Does not compile

これは、非常に厄介な実行時エラーのクラス全体をキャッチする比較的安価な方法であるため、変換の非推奨は、「より優れた C」としての C++ の一般的な哲学と非常に一致しています。

さらに、コード セグメント 2 は、ポインターの内容が保護されているという事実を無効にしません。上書きされるのはポインター自体であり、その内容ではありません。と には違いがありconst char *ptrますchar * const ptr。前者はコンテンツを保護します。後者はポインタ自体を保護します。この 2 つを組み合わせて、ポインタとその内容を .xml として保護できますconst char * const ptr

于 2012-11-07T17:50:40.963 に答える
0

char const *からchar * への暗黙的な変換がないため、構文が間違っています。

文字列リテラルの型は、C および C++ ではずっとchar const *でした。(非常に古い C については間違っている可能性があります。)

規則の変更は、文字列リテラルの型とは何の関係もありませんが、ポインター型間の許可された変換とは関係ありません。

const へのポインターは不変であるため、変換は間違いです。コンパイル時およびリンク時に定数であることがわかっている値である文字列リテラルは、読み取り専用メモリ セグメントに配置される場合があります。

于 2012-11-07T17:49:54.773 に答える