【C++】externとは?|使い方と宣言・定義の違いをわかりやすく解説

サムネイル画像 C++

今回は、C++での「extern」について解説していきます。

複数のファイルでグローバル変数を共有したいとき、「どうやって他のファイルから変数を使えばいいの?」と疑問に思ったことはありませんか?

この記事を読み終えると、あなたはexternの使い方をマスターできると思いますので、ぜひ最後まで読んでいただけると嬉しいです。

externとは?

externとは、

・「この変数は別のファイルで定義されていますよ
コンパイラに伝えるための宣言

です。

C++では、複数のソースファイルで同じグローバル変数を使いたい場合、extern宣言が必要になります。

通常、変数は「宣言」と「定義」が同時に行われますが、externを使うことで「宣言だけ」を行うことができるのです。

なぜexternが必要なの?

コンパイルはファイル単位で行われます。

そのため、あるファイルで定義したグローバル変数を別のファイルで使おうとすると、コンパイラは「そんな変数は知らない」とエラーを出してしまいます。

例えば、こんなコードを書いたとします。

▼main.cpp

#include <iostream>

int g_count = 0; // グローバル変数を定義

void sub();

int main() {
    sub();
    return 0;
}

▼sub.cpp

#include <iostream>

void sub() {
    std::cout << "count = " << g_count; // エラー!
}

このコードはコンパイルエラーになります。

なぜなら、sub.cppをコンパイルする際に、コンパイラがg_countという変数を知らないからです。

そこで、extern宣言の出番です。

externの使い方

extern宣言は次のように書きます。

extern データ型 変数名;

先ほどのコードを修正してみましょう。

▼sub.cpp

#include <iostream>

extern int g_count; // 外部で定義された変数を宣言

void sub() {
    std::cout << "count = " << g_count << std::endl; // これでOK!
}

この一行を追加するだけで、コンパイラに「g_countはどこか別のファイルで定義されているよ」と伝えることができます。

ヘッダファイルでexternを使う

実際の開発では、ヘッダファイルにextern宣言をまとめるのが一般的です。

▼main.h

#ifndef MAIN_H
#define MAIN_H

extern int g_count; // ヘッダでextern宣言

#endif

▼main.cpp

#include <iostream>
#include "main.h"

int g_count = 0; // 変数の定義と初期化

void sub();

int main() {
    g_count++;
    sub();
    return 0;
}

▼sub.cpp

#include <iostream>
#include "main.h" // ヘッダをインクルードするだけ

void sub() {
    std::cout << "count = " << g_count << std::endl;
}

こうすることで、main.hをインクルードするだけでどのファイルからでもg_countを使えるようになります。

宣言と定義の違い

ここで重要なポイントが「宣言」と「定義」の違いです。

  • 宣言変数の存在をコンパイラに知らせるだけ(何度書いてもOK)
  • 定義メモリ領域を確保する(プログラム全体で1回だけ)

通常、int g_count = 0;と書くと、宣言と定義が同時に行われます。

しかし、externを付けると「宣言だけ」になるため、複数のファイルで書いてもエラーになりません。

extern使用時の注意点

1. 定義は必ず1回だけ

extern宣言だけを書いて、どこにも定義がないとリンクエラーになります。

必ずどこか1つのファイルで定義してください。

2. 初期化はできない

extern宣言と同時に初期化することはできません。

extern int g_count = 0; // これはNG!

初期化は定義を行うファイルで行います。

3. グローバル変数の乱用は避ける

externを使えば便利ですが、グローバル変数を多用すると、どこで値が変わったのか追いにくくなります。

本当に必要な場合だけ使うようにしましょう。

配列でのexternの使い方

配列のグローバル変数にもexternを使うことができます。

▼main.h

extern int numbers[]; // 要素数は省略可能

▼main.cpp

int numbers[] = {1, 2, 3, 4, 5}; // 配列の定義

ただし、extern宣言時に要素数を書かないと、sizeofで配列のサイズを取得できません。

サイズが必要な場合は、次のように書きます。

▼main.h

constexpr int ARRAY_SIZE = 5;
extern int numbers[ARRAY_SIZE];

関数にはexternは不要

関数のプロトタイプ宣言には、externを付ける必要はありません。

void func(); // これだけでOK(externは不要)

関数の宣言は「定義を伴わない」ことが明確なため、externを付けなくても宣言だけと見なされます。

まとめ

extern宣言は、複数ファイルでグローバル変数を共有するための仕組みです。

  • 変数の定義は1つのファイルで行う
  • 他のファイルではextern宣言で使えるようにする
  • ヘッダファイルにextern宣言をまとめるのが一般的

これでexternの使い方はバッチリですね!

複数ファイルで開発する際に、ぜひ活用してみてください。

ここまで読んでくださり、ありがとうございました。

この記事が皆様の学習に役立てば幸いです。