文字列定数から 'char *'への変換がCでは有効であるがC ++では無効である理由


163

C ++ 11標準(ISO / IEC 14882:2011)は次のように述べてい§ C.1.1ます。

char* p = "abc"; // valid in C, invalid in C++

C ++の場合、文字列リテラルへのポインタは有害であり、変更しようとするとクラッシュするため、問題ありません。しかし、なぜCでは有効なのでしょうか。

C ++ 11はまた言います:

char* p = (char*)"abc"; // OK: cast added

つまり、最初のステートメントにキャストが追加された場合、それは有効になります。

キャストによって2番目のステートメントがC ++で有効になるのはなぜですか?それは最初のステートメントとどう違うのですか?まだ有害ではないですか?もしそうなら、なぜ規格はそれが大丈夫だと言ったのですか?


3
C ++ 11は最初のものを許可しません。そもそもなぜCが文字列リテラルの型を作ったのか、私にはわかりませんchar[]。2つ目はconst_cast変装です。
クリス

4
このルールが変更された場合に壊れるレガシーCコードが多すぎます。
Paul R

1
基準が2番目とするテキストを引用してくださいOK
Nawaz、2014年

13
C言語にはそれ以前の文字列リテラルconstがあったため、必ずしもそうではありませんでしたconst
ケーシー

2
CおよびC ++では、ほぼすべての型から別の型にキャストできます。これは、これらのキャストが意味があり安全であることを意味するものではありません。
Siyuan Ren

回答:


207

C ++ 03までは、最初の例は有効でしたが、非推奨の暗黙的な変換を使用していました。文字列リテラルはchar const *、その内容を(未定義の動作を引き起こすことなく)変更できないため、typeとして扱う必要があります。

C ++ 11以降、非推奨となった暗黙の変換は公式に削除されたため、それに依存するコード(最初の例のように)はコンパイルされなくなります。

コードをコンパイルできるようにする方法の1つを説明しました。暗黙的な変換は削除されていますが、明示的な変換は引き続き機能するため、キャストを追加できます。私は考えていない、しかし、この「固定」のコードを考えてみましょう。

コードを真に修正するには、ポインターのタイプを正しいタイプに変更する必要があります。

char const *p = "abc"; // valid and safe in either C or C++.

なぜC ++で許可されたのか(そしてCでも許可されています):その暗黙の変換に依存する既存のコードがたくさんあり、そのコードを(少なくとも公式の警告なしに)破壊することは、標準委員会のように思われました悪い考え。


8
@rullof:少なくとも移植性を(まったく)考慮しているコードにとっては、意味のある柔軟性をもたらさないほど危険です。文字列リテラルへの書き込みは、通常、最新のOSでプログラムを中止するため、コードに(書き込みを)許可しても、意味のある柔軟性は追加されません。
Jerry Coffin 2014年

3
この回答で提供されているコードスニペットchar const *p = "abc";は「C C ++の両方で有効かつ安全」であり、「C または C ++のどちらでも有効かつ安全」ではありません。
Daniel Le

4
@DanielLeこれらの文はどちらも同じ意味です
Caleth

3
あらまあ!【舌をしっかり頬に挿入】申し訳ありませんが、ここでは「or」が正しい言葉です。コードはCまたはC ++としてコンパイルできますが、CとC ++の両方として同時にコンパイルすることはできません。どちらかを選択できますが、選択する必要があります。両方を同時に持つことはできません。[通常の舌操作を再開]。
ジェリーコフィン

2
いいえ、両方/およびここで最も明確で正しい表現です。 どちらか一方または両方が正しい意味を伝えることもありますが、技術的にはそれほど明確ではありません。 または、単独では間違いなく間違っています(AまたはBAおよびBと等しくありません)。
Apollysはモニカの2018

15

歴史的な理由からCでは有効です。Cは伝統的に、文字列リテラルの型はではchar *なくであると指定していましたが、const char *実際には変更することは許可されていないということで修飾しました。

キャストを使用するときは、基本的にコンパイラーにデフォルトの型マッチング規則よりもよく知っていることを伝えているので、割り当ては問題ありません。


3
char[N]、に変更されましたconst char[N]。サイズ情報がついています。
クリス

1
C文字列リテラルのタイプであるでchar[N]はなく、char*例えば"abc"あるchar[4]
Grijesh Chauhan

2

strdupを使用することもできます

char* p = strdup("abc");
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.