メモリ管理がどのように機能するかを理解する必要があります。配列data
を静的に割り当てたので、スタックに配置されます (呼び出された関数のローカル変数を持つフレームを保持します)。スタックはすべてのプロセスに静的に割り当てられます (つまり、プロセスの有効期間を通じて一定のサイズになります)。
今から、スタックは次のようになります。
data[1, 0, 0, 3, 4]
これで、関数が呼び出されましたfunction
。新しいフレームがスタックに置かれたので、次のようになります。
data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b]
(main data) (function data)
ここで、データを型にキャストします。そのサイズは少なくとも 6 バイトです (クラスの内容の配置によっては、8 バイト以上かかる場合があると仮定しましょう)。したがって、これらのバイトにアクセスしようとします:
data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b]
(main data) (function data)
* * * * * *
(私のスタックの視覚化は単純化されていることに注意してください。関数を呼び出した後に、より多くのデータが残っている可能性があります)。
後のprintf中にアクセスするすべてのメモリはアプリケーションに属しているため、OSはアクセス違反エラーを発生させません。データを読み取るので、何も損傷しません。しかし、ここで、何かを に書き込むとしpTest->var3
ます。これらのバイトは上書きされます:
data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b]
(main data) (function data)
* * # # # #
そして今見てください、あなたは return-pointer を損傷しました - ほとんどの場合、プログラムを終了function
して に戻ろうとしてクラッシュする可能性がありますmain
。
一般に、互換性のある (同じサイズの) データ型のみをキャストすることを強くお勧めします。多くの場合、コンパイラは、キャストが有効かどうかを知る方法がありません (特に、void *
途中でポインターをキャストする場合)。そのため、プログラムでのキャストの作成には細心の注意を払う必要があります。