「値がプログラムの間、ずっと保持される変数」と説明すると、
static変数とグローバル変数は同じものに見えてしまいます。
この記事では、その2つの決定的な違いである、「どこからアクセスできるか」
という点を、実際に動くコード例で整理します。
・グローバル変数の基本(宣言場所
・スコープ)
・static変数の基本(宣言場所
・スコープ
・値の保持)
・2つの決定的な違い(アクセスできる範囲)
・どちらを使うべきかの判断基準
なぜ2つを混同しやすいのか
まず、混同が起きやすい理由を整理します。
両方「値が保持される」という共通点
グローバル変数も、static変数も、プログラムが動いている間、
値が消えずに保持される点は共通しています。
このセッションで見つかった混同の実例
・既存記事の見直し作業で、static変数の使い方に関する指摘が複数回発生した
・『値が保持される』という性質だけを見て、グローバル変数と同じ感覚で使ってしまうミス
・この記事では、スコープの違いを軸に整理し直します
この記事で整理する範囲
構造体の値渡し・参照渡しは、既刊の構造体記事で扱ったため、
本記事では変数のスコープと寿命だけを扱います。
グローバル変数の基本
まず、グローバル変数の仕様を確認します。
宣言場所(関数の外)
int g_tickCount = 0; //関数の外で宣言する
関数の外(プログラムのどこにも属さない場所)で、宣言した変数がグローバル変数です。
スコープ(プログラム全体からアクセス可能)
グローバル変数は、ファイル内のどの関数からでも、読み書きできます。
初期化タイミング
グローバル変数は、プログラムが読み込まれた時点で、一度だけ初期化されます。
static変数(ローカルstatic)の基本
次に、static変数の仕様を確認します。
宣言場所(関数の中)
void SomeFunction()
{
static int s_count = 0; //関数の中でstaticを付けて宣言する
}
関数の中で`static`キーワードを付けて、宣言した変数がstatic変数です。
スコープ(その関数の中だけ)
static変数は、それを宣言した関数の中でしか、読み書きできません。
値が保持される仕組み(呼び出しをまたいで保持)
通常のローカル変数は、関数が終わるたびに値が消えますが、
static変数は次の呼び出しでも、
前回の値を覚えています。
2つの決定的な違い:スコープ
ここが、この2つを区別する上で、最も重要なポイントです。
どこからでも読み書きできるか、関数内に閉じているか
グローバル変数はプログラム全体から、static変数は宣言した関数の中だけから、
それぞれアクセスできます。
名前の衝突リスクの違い
グローバル変数を増やすほど、どこで値を変更したか追跡しづらくなり、
名前の衝突リスクも高まります。
static変数は関数内に閉じているため、このリスクが小さくなります。
実装例で比較する
次の見出しで、同じ「回数を数える」処理を、両方の書き方で実装して比較します。
実際に動くコード全体(ティックカウンターで比較)
OnTick()が呼ばれた回数を、
グローバル変数とstatic変数の両方で数えて比較します。
//+------------------------------------------------------------------+
//| StaticVsGlobalDemo.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property strict
int g_tickCount = 0; //グローバル変数(プログラム全体からアクセス可能)
void CountWithStatic()
{
static int s_tickCount = 0; //static変数(この関数の中だけで保持)
s_tickCount++;
Print("static変数(CountWithStatic内のみ有効): ", s_tickCount);
}
void OnTick()
{
g_tickCount++;
CountWithStatic();
Print("グローバル変数(どこからでも読める): ", g_tickCount);
// 次の行はコンパイルエラーになる。
// s_tickCountはCountWithStatic()の中だけのスコープのため、
// OnTick()からは見えない。
// Print("static変数: ", s_tickCount);
}
MetaEditorでのコンパイル・実行手順
MetaEditorで保存してコンパイルし、エラーが0件であることを確認したうえで、
デモ口座のチャートに適用して、ログに2つの数値が記録されることを確認します。
よくあるエラーと落とし穴
実際に使う前に、確認しておきたい落とし穴です。
static変数を「リセットしたい」のにできない
・static変数は関数が呼ばれるたびにリセットされるわけではない
・値をリセットしたい場合は、条件を満たした時に自分で0を代入する必要がある
・『static=毎回リセットされる』という誤解に注意してください
グローバル変数の多用で起きる名前衝突・追跡困難
EAやインジケーターが大きくなるほど、グローバル変数を増やしすぎると、
どこで値が変わったのかを追うのが難しくなります。
OnDeinit/OnInitと値の保持の関係
入力パラメータを変更した際などに、
`OnDeinit()`と`OnInit()`が呼ばれても、
グローバル変数・static変数の値は、
プログラムが完全に外れるまで保持される場合があります。
挙動は環境により変わるため、
重要な値はファイルや`GlobalVariableSet`系の、
永続化手段も検討してください。
どちらを使うべきかの判断基準
実務上の使い分けの基準です。
・複数の関数から共有したい値→グローバル変数
・1つの関数の中だけで「前回の状態」を覚えたい値→static変数
・迷ったら、まずstatic変数で関数内に閉じられないか検討する
よくある質問
static変数とグローバル変数について、よくある疑問に回答します。
static変数はインジケーターのバーごとに初期化されますか?
されません。
`OnCalculate()`が何度呼ばれても、
その中で宣言したstatic変数は値を保持し続けます。
構造体の値渡し・参照渡しとは別の話ですか?
別の話です。
値渡し・参照渡しは「関数に渡すときのコピーの有無」、
static変数とグローバル変数は「変数自体の宣言場所とスコープ」の違いです。
既刊の構造体記事もあわせて確認してください。
input変数をグローバル変数の代わりに使えますか?
input変数もプログラム全体から読めますが、実行中に値を書き換えることはできません。
書き換えが必要な値は、通常のグローバル変数として別に用意してください。
【MQL】static変数とグローバル変数の違いについて解説してみた(MQL4/MQL5共通):まとめ
static変数とグローバル変数は、どちらも値が保持される点は共通していますが、
アクセスできる範囲(スコープ)が決定的に異なります。
複数の関数から共有したい値はグローバル変数、
1つの関数の中だけで前回の状態を覚えたい値はstatic変数、
という基準で使い分けてみてください。
グローバル変数を増やしすぎると、追跡が難しくなる点にも注意してください。
コメント