C文字列リテラルはではないため、Cコンパイラは最初のエラーを検出する必要はありませんconst
。
C99標準のN1256ドラフトを参照してください:
6.4.5パラグラフ5:
変換フェーズ7では、値ゼロのバイトまたはコードが、1つまたは複数の文字列リテラルから生じる各マルチバイト文字シーケンスに追加されます。次に、マルチバイト文字シーケンスを使用して、シーケンスを含めるのに十分な静的ストレージ期間と長さの配列を初期化します。文字列リテラルの場合、配列要素の型はcharであり、マルチバイト文字シーケンスの個々のバイトで初期化されます。[...]
パラグラフ6:
それらの要素が適切な値を持っている場合、これらの配列が別個であるかどうかは指定されていません。プログラムがそのような配列を変更しようとした場合、動作は未定義です。
(C11はこれを変更しません。)
したがって、文字列リテラル"hello, world"
はchar[13]
(ではなく )型であり、ほとんどのコンテキストでconst char[13]
変換されます。char*
オブジェクトを変更しようとするとconst
動作が定義されておらず、変更しようとするほとんどのコードはコンパイラーによって診断される必要があります(たとえば、キャストでそれを回避できます)。文字列リテラルを変更しようとすると、未定義の動作が発生しますが、それが原因でconst
はありません(そうではありません)。これは、標準で動作が未定義であると具体的に規定されているためです。
たとえば、このプログラムは厳密に準拠しています。
#include <stdio.h>
void print_string(char *s) {
printf("%s\n", s);
}
int main(void) {
print_string("Hello, world");
return 0;
}
文字列リテラルがの場合、(非)をとる関数const
に渡すには診断が必要になります。プログラムは有効ですが、が指す文字列を変更しようとすると、未定義の動作を示します。"Hello, world"
const
char*
print_string()
s
その理由は歴史的です。Pre-ANSI Cにはキーワードがなかったため、aを取り、それが指すものを変更しないことを約束const
する関数を定義する方法はありませんでした。char*
ANSI C(1989)で文字列リテラルを作成const
すると、既存のコードが壊れてしまい、標準の以降のエディションでそのような変更を行う良い機会がありませんでした。
gccは、-Wwrite-strings
文字列リテラルをとして処理しますconst
が、これに対する診断を発行できないため、gccを不適合コンパイラにします。
const char (*p)[6] = &"hello";
("hello"
はタイプchar[6]
であるため、&"hello"
はタイプchar (*)[6]
であり、宣言されたタイプのとは互換性がありませんp
。で-Wwrite-strings
、はタイプ&"hello"
として扱われconst char (*)[6]
ます。)おそらくこれが理由であり、。-Wall
も-Wextra
含まれていません-Wwrite-strings
。
一方、警告をトリガーするコードは、-Wwrite-strings
とにかく修正する必要があります。Cコードを記述して、診断の有無にかかわらずコンパイルできるようにすることは悪い考えではありません-Wwrite-strings
。
( BjarneStroustrupがC++を設計していたとき、彼は古いCコードとの厳密な互換性についてそれほど心配していなかったため、C ++文字列リテラルであることに注意してください。) const