ネイティブ C 配列は境界チェックを受けません。これには、追加の命令とデータ構造が必要になります。C は効率とリーンネスを重視して設計されているため、安全のためにパフォーマンスを犠牲にする機能は指定されていません。
valgrind のようなツールを使用できます。これは一種のエミュレーターでプログラムを実行し、どのバイトが初期化され、どのバイトが初期化されていないかを追跡することで、バッファー オーバーフローなどを検出しようとします。しかし、たとえば、オーバーフローしたアクセスがたまたま別の変数への正当なアクセスを実行した場合など、絶対確実ではありません。
内部的には、配列のインデックス付けは単なるポインター演算です。と言うとき、特定のオブジェクトのアドレスを取得するために、 1 つの要素arr[ 150 ]
の 150 倍を追加し、それを のアドレスに追加するだけです。そのアドレスは単なる数字であり、ナンセンス、無効、またはそれ自体が算術オーバーフローである可能性があります。これらの条件のいくつかは、アクセスするメモリが見つからない場合やウイルスのような活動を検出できない場合に、ハードウェアがクラッシュを生成する結果となりますが、ソフトウェア フックの余地がないため、ソフトウェアによって生成された例外は発生しません。安全な配列が必要な場合は、加算の原則に基づいて関数を構築する必要があります。sizeof
arr
ちなみに、あなたの例の配列は技術的にも固定サイズではありません。
int len = 10; /* variable of type int */
char arr[len]; /* variable-length array */
非const
オブジェクトを使用して配列サイズを設定することは、C99 以降の新機能です。関数パラメーター、ユーザー入力などにすることもできlen
ます。これは、コンパイル時の分析に適しています。
const int len = 10; /* constant of type int */
char arr[len]; /* constant-length array */
完全を期すために: C 標準では境界チェックは指定されていませんが、禁止されているわけでもありません。これは、未定義の動作、またはエラー メッセージを生成する必要のないエラーのカテゴリに分類され、影響を与える可能性があります。セーフ配列を実装することは可能であり、機能のさまざまな近似が存在します。Cは、たとえば、配列 B から任意のオブジェクト A にアクセスするための正しい範囲外インデックスを見つけるために、2 つの配列の違いを取ることを違法にすることによって、この方向にうなずきます。しかし、この言語は非常に自由です。 A と B が同じメモリ ブロックの一部であるmalloc
場合は有効です。つまり、C 固有のメモリ トリックを使用すればするほど、C 指向のツールを使用しても自動検証が難しくなります。