「値がプログラムの間、ずっと保持される変数」と説明すると、

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変数、

という基準で使い分けてみてください。

グローバル変数を増やしすぎると、追跡が難しくなる点にも注意してください。

関連記事