こんにちは、ナナです。
メモリの種類の1つ目として「プログラムメモリ」について紹介します。
「プログラムメモリ」とはその名の通り、プログラムが配置されるメモリのことです。プログラムが配置されるとはどのような意味があるのかを解説します。扱う上での注意点もあります。
本記事では次の疑問点を解消する内容となっています。
では、プログラムメモリの扱いを学んでいきましょう。
プログラムメモリの特徴を知ろう
師匠!「メモリ」はポインタでたくさん学びましたが、まだ学ぶことがあるのですか?プログラミングの世界は学ぶものが尽きません。
そうなんだよ。プログラミングの世界の深淵はまだ見えてないんだよ。もっとメモリというものを掘り下げていくよ。
プログラムメモリの特徴
プログラムメモリは、他のメモリと比べて次の特徴を持ちます。
種類 | 配置データ | Read/Write | 容量 | 説明 |
プログラムメモリ | 関数・定数 | R | 大サイズ | 関数や定数が配置 |
スタックメモリ | 変数 | R/W | 小サイズ | 関数内で定義した変数が配置 |
静的メモリ | 変数 | R/W | 中サイズ | 関数外で定義した変数が配置 |
動的メモリ | 変数 | R/W | 大サイズ | メモリ確保関数で取得 |
他のメモリに対して、特徴的なのがRead専用なことですね。
つまり、
プログラム実行中に、このメモリに対する値の書き換えは禁止されることになります。
書き換えが禁止。これは非常に大きな特徴です。関数を書き換えることはないですが、定数領域を間違えて書き換えようとするとシステムが異常終了します。
関数はプログラムメモリに配置される
師匠!「メモリ」というものにこんなに種類があったのですか?私が作った関数は「プログラムメモリ」という場所に置かれるのですか?
そうです。皆さんが作った関数はリンカによって「プログラムメモリ」というメモリ領域に配置されるんです。
関数ポインタの記事『C言語 関数ポインタ【ポインタを使って関数を呼ぶ仕組み解説】』にて、皆さんが作成した関数はメモリ上で管理されていると解説しました。
皆さんの作り出した関数は、プログラムメモリ上にて管理されることになります。
組み込み開発の世界でも「プログラムメモリ」は比較的大きなメモリサイズが割り当てられます。関数をたくさん作ってもメモリサイズがはみ出ることは比較的少ないですね。
定数のプログラムメモリへの配置
師匠!関数以外にもプログラムメモリに配置されるものはあるのでしょうか?
組み込み開発では、const修飾子を使った変数はプログラムメモリ上に配置されます。
Windowsアプリケーションといった汎用PC向けでは該当しませんが、組み込み開発においてはconstを付与した変数はプログラムメモリに配置されます。
constを使った定数化した変数
C言語では「const」という修飾子を使うと変数の値を書き換えることができない「定数」とすることが可能です。
#include <stdio.h>
// num変数の定数化
const long num = 100;
int main(void)
{
// 定数化した変数は書き換え不可
num = 200;
return 0;
}
このような定数化した変数への代入はコンパイラによってエラーが検知されます。
main.c(9): error C2166: 左辺値は const オブジェクトに指定されています。
このような定数はプログラム実行中に書き換えることがないため、組み込み開発の環境ではプログラムメモリに配置されます。
constの扱いに関しては詳細を別記事『C言語 constの利用価値【変数を定数化する方法と利用シーン】』にまとめてありますので、興味がある方は見てください。
変数のメモリ領域よりもプログラムメモリの方がサイズは余裕があるケースが多いです。そのため組み込み開発では、テーブルデータといった巨大な固定データはconstを付与してプログラムメモリに配置します。
文字列リテラルもプログラムメモリに配置される
文字を扱う記事『C言語 文字と文字列を図解【何が違うのこの2つ?解決します】』の中で、「文字列リテラル」という言葉が出てきました。
文字列リテラルも定数という扱いであり、プログラムメモリに配置されます。
#include <stdio.h>
int main(void)
{
// 文字列リテラル"Hello"
char * pmoji = "Hello";
printf("%s", pmoji);
return 0;
}
この例で示した”Hello”という文字が管理されているメモリは、プログラムメモリになります。
文字列リテラルはダブルクォーテーションで囲まれた文字でしたね。
文字列リテラルのメモリを変更することは禁止!
そのため、次のように文字列リテラルのメモリ内容を書き換える行為はしてはなりません。
#include <stdio.h>
int main(void)
{
// 文字列リテラルへのポインタを用意
char * pmoji = "Hello";
// ポインタから文字列リテラルを書き換え
*pmoji = 'A';
return 0;
}
このプログラムは初心者のうちは結構やりがちなのですが、実行すると次のように「例外」と呼ばれるシステム異常が発生します。
ポインタを使った文字列の扱いは、もう少し先で再度学習します。