C言語編 第23章 複数ファイルによるプログラム

先頭へ戻る

この章の概要

この章の概要です。


規模の大きいプログラム

ここまでに登場したプログラムは、どれも1つのソースファイルだけで完結していました。しかし、もう少し規模の大きなプログラムを作るときには、ソースファイルを複数個に分割することが一般的です。

「1つのソースファイルだけで完結していた」と書いたばかりですが、本当はこれまでのプログラムでも、複数のファイルが関わっています。プログラムの先頭でいつも書いていた以下のような1文、

#include <stdio.h>

これが、複数のファイルを連携させてプログラムを作るカギになります。

この記述の意味は、「stdio.h というファイルの内容を、この位置に取り込め」というものです。.h という拡張子を持つファイルを、C言語ではヘッダファイル、あるいは単にヘッダと呼びます。

Windows においての拡張子についての説明が「資料集 - Windows - 拡張子」にあります。

規格に厳密に従えば、< と > で囲まれた部分は、処理系が最終的に取り込むべき内容物を判断できるのであれば、ファイル名である必要はありません。その点を踏まえると、ヘッダファイルと呼ぶよりも、単にヘッダと呼ぶ方が適切ではあります。

大抵の環境では、<stdio.h> などのヘッダファイルが、開発環境の中にあります。普通、コンパイラメーカーが、コンパイラとセットで出荷しており、コンパイラをインストールしたときに自動的に作成されています。このように、C言語の標準規格が、用意すべきであることを明示しているヘッダが幾つかありますが、これらのことを標準ヘッダと呼びます。標準ヘッダには、標準関数など、これまたやはり標準規格によって定められた「必要なもの一式」が記述されています。

標準ヘッダと、その中に含まれている機能の一覧が、「標準ライブラリのリファレンス(ヘッダ別)」にあります。

正確にいえば、<stdio.h> のような幾つかの標準ヘッダについては用意しなくてもよいとされている環境もあります。これは、フリースタンディング環境と呼ばれ、OS が存在しないような実行環境のことをいいます。一方、OS の制御下でプログラムを実行できる環境は、ホスト環境といいます。

このように、C言語のコンパイラは、C言語の標準規格が定めたルールに従って、標準ヘッダを用意しており、そのおかげで、どのコンパイラでも共通のプログラムがコンパイルできるのです。

話を戻しますが、ほとんどのプログラムは複数のファイルの連携で成り立っています。C言語では、主に .c という拡張子を持つファイル(一般にこれをソースファイルと呼びます)と、主に .h という拡張子を持つヘッダファイルを作ります。拡張子には制約はないので、他の名前を使っても構いません。

巨大なプロジェクトになると、ソースファイルとヘッダファイルの総数が数千個、あるいはそれ以上にもなることがあります。これまでの章で何度か書いてきた、「スコープは極力狭くするべき」「分かりやすい名前を付けるべき」「部品化することを考えるべき」といったガイドラインは、こういった巨大なプロジェクトを構築し、維持管理するために非常に重要です。

ヘッダファイル

ヘッダファイルは #include を使って、その内容を取り込んで使います。#include の意味は、「指定したヘッダの内容を、この記述を書いた箇所へ取り込む」ということです。この行為をよく「ヘッダをインクルードする」と表現します。

さて、ここでは自分でヘッダファイルを作ってみましょう。拡張子に制約はありませんが、ここでは一般的なやり方に従って、.h とします。ここでは、utility.h という名前のヘッダファイルを作ります。

VisualStudio でヘッダファイルを作成する方法は、こちらのページにあります。

utility.h の内容は以下のようにします。

/* 大きい方の値を返す */
int max(int a, int b);

/* 小さい方の値を返す */
int min(int a, int b);

このヘッダファイルに記述されている内容は、関数プロトタイプだけです。通常、ヘッダファイルには関数の定義は書きません。定義はソースファイルの方に記述します

イメージとしては、ヘッダファイルは、カタログとかメニュー表のようなものです。具体的な処理工程(実装)は、ソースファイルの方にありますが、その具体的な部分を気にせずに、ヘッダファイルを経由して使わせてもらうという感覚です。これは例えば、<stdio.h> にあるカタログから printf関数を選んで使わせてもらっているのと同じです。printf関数の具体的な定義は、stdio.h ではなく、対応するソースファイル(これは大抵の製品では非公開です)に入っていて、それを気にせずに使えるという構図です。

これまた "一般的には" ということになりますが、ヘッダファイルとソースファイルを対応付けるように作るのが基本です。つまり、utility.h に対応して utility.c を作るということです。utility.c は次のようにしてみます。

#include "utility.h"

/* 大きい方の値を返す */
int max(int a, int b)
{
    if( a >= b ) {
        return a;
    }
    return b;
}

/* 小さい方の値を返す */
int min(int a, int b)
{
    if( a <= b ) {
        return a;
    }
    return b;
}

ソースファイルの方には、ヘッダファイルで宣言した関数の定義を記述します。

対応するヘッダファイルがあるソースファイルでは、必ず、そのヘッダファイルを1番最初にインクルードするように徹底して下さい。これはそうする必要がない場合もありますが、常にこうするように書いた方が余計なトラブルを防げます。

なお、自分で用意したヘッダファイルをインクルードする場合は、<stdio.h> のように < と > で囲む形式ではなく、"" で囲む形式を使います。

本当のところ、両者の差は、どのディレクトリ(フォルダ)からヘッダファイルを探すかの違いですが、使い分けの基準としては、先ほどの考え方で問題ありません。

残すは、これらの関数を実際に使う側の準備です。そもそも、まだ main関数がありませんから、これだけでは実行できません。それでは、main関数を含んだ main.c を作成してみましょう。

#include <stdio.h>
#include "utility.h"

int main(void)
{
    int a = 50;
    int b = 100;

    printf( "MAX: %d\n", max(a,b) );
    printf( "MIN: %d\n", min(a,b) );

    return 0;
}

実行結果:

MAX: 100
MIN: 50

ここまでに用意した max関数と min関数の定義は、utility.c に書かれている訳ですが、#include で取り込むのは utility.h の方です。すると、utility.h に記述した関数プロトタイプが取り込まれるので、max関数と min関数が見える場所に置かれることになります。こうして、main.c から呼び出すことが可能になります。


ビルドと実行

VisualStudio のような開発環境を使っているとすると、プログラムを作成した後、「ビルド (build)」を行い、何もエラーが出なければ、「実行 (Run)」して動作を確認すると思います。

VisualStudio でビルドを行う方法はこちらのページに、実行を行う方法はこちらのページにあります。

ビルドには、コンパイルリンクといった複数の過程が含まれています。

コンパイルとは、ソースコードを翻訳して、別の言語に置き換える過程を指します(ここでの言語というのは、プログラミング言語の話であって、日本語とか英語とかいう意味ではありません)。また、コンパイルを行うプログラムをコンパイラといいます。

VisualStudio はコンパイルもできるし、リンクもできるし、デバッグ作業もできるし、ソースコードを書くエディタも持っているので、単に「コンパイラ」と呼ぶのは本来適切ではありません。コンパイルは、持っている機能の1つに過ぎません。このような開発に必要な複数の機能がひとまとめになって提供されている環境を、統合開発環境(IDE)と呼びます。

コンピュータの世界の言語には、人間が比較的読みやすい高級言語と、人間には読みづらいがコンピュータが簡単に理解できる低級言語があります。この区別は明確なものではなく、言語1つ1つにおいて読みやすさの段階はあります。C言語は高級言語に近いと言えます。

コンパイルは、高級の側に近い言語を、低級の側に近い言語へと翻訳します。多くの場合、マシン語(機械語)と呼ばれる、最も低級な言語へと翻訳します。なぜかというと、コンピュータが直接的に理解できて、実行できる言語はマシン語だけだからです。そのため本当なら、プログラムというものは、マシン語で書かないといけないのですが、「最も低級な言語」と言ったように、人間がマシン語を覚えてプログラムを書き上げることは、ほとんど不可能に近い作業なのです。そこで、C言語のような、人間が読みやすい形の言語が多数考案されたのです。

さて、1つのプログラムには、複数のソースファイルが含まれていることがあるので、1つ1つのファイルをコンパイルしたところで、全体像が見えないと正しく動作できません。

例えば、先程のサンプルでいうと、utility.c だけをコンパイルしても、そこには main関数が含まれていませんから、実行をどこから始めればよいか分かりません。一方で、main.c だけをコンパイルしても、そこで使われている max関数や min関数の定義がありませんから、関数呼び出しを行った結果、何を実行すればいいのかわかりません。

そこで、1つ1つのソースファイルは、それぞれをオブジェクトファイルという、いわば中間的な言語に翻訳して書き出しておきます。そして、1つのプログラム全体を形作るのに必要なオブジェクトファイルが出揃ったところで、これらを1つにまとめようとします。このまとめる過程のことをリンクと呼び、リンクを行うプログラムをリンカといいます。

VisualStudio ならば、ビルドを行った後、エクスプローラでプロジェクトのあるフォルダを覗くと、Debug という名前のフォルダが作成されていることが分かります。この中にある .obj という拡張子のファイルがオブジェクトファイルです。ソースファイルの名前と同じ名前で、拡張子だけが異なるファイルが作成されているはずです。

複数のオブジェクトファイルがリンクされた結果、1つの実行可能ファイルが作成されます(Windows であれば .exe という拡張子を持ちます)。この実行可能ファイルは、Windows のエクスプローラなどから実行できる状態になっています。VisualStudio で、実行のコマンドを選択したときに実行されているのは、こうして生成された実行可能ファイルです。

VisualStudio でビルドを行うと、そのときの設定に応じて、Debugフォルダや Releaseフォルダの中に実行可能ファイルが生成されています。

extern と外部結合

さて、今度は main.c、print.c、print.h という 3つのファイルを用意します。

/* main.c */
#include "print.h"

int main(void)
{
    printNum( 100 );
    printNum( 200 );
    printNum( 300 );

    return 0;
}
/* print.c */
#include <stdio.h>
#include "print.h"

int gLastPrintNum = 0;

void printNum(int num)
{
    printf( "[[ %d ]]\n", num );
    gLastPrintNum = num;
}
/* print.h */

void printNum(int num);

実行結果:

[[ 100 ]]
[[ 200 ]]
[[ 300 ]]

printNum関数は、引数で指定された int型の整数を [[ ]] で囲んで出力します。また、もう1つの機能(?) として、最後に出力した整数をグローバル変数gLastPrintNum に保存しています。

ここで、main.c から gLastPrintNum を使いたいとしましょう。main.c を次のように書き換えてビルドを行ってみます。

/* main.c */
#include <stdio.h>
#include "print.h"

int main(void)
{
    printNum( 100 );
    printNum( 200 );
    printNum( 300 );

    printf( "%d\n", gLastPrintNum );  /* コンパイルエラー */

    return 0;
}

これはコンパイルエラーになります。main.c は print.h を #include で取り込んでいますが、gLastPrintNum が宣言されているのは print.c の方なので、main.c からは可視でない(第22章)ためです。グローバル変数はファイルスコープである(第22章)ことも思い出しましょう。

それなら、main.c にも gLastPrintNum を宣言したらどうでしょう?

/* main.c */
#include <stdio.h>
#include "print.h"

int gLastPrintNum = 0;  /* リンクエラー */

int main(void)
{
    printNum( 100 );
    printNum( 200 );
    printNum( 300 );

    printf( "%d\n", gLastPrintNum );

    return 0;
}

今度は、コンパイルの過程は成功していますが、リンクの過程でエラーになります。このエラーは、重複宣言と呼ばれるものです。重複宣言は、同じブロック内や、関数の外側に、同じ名前の定義が複数登場したときに起こります。今回の場合、main.c の関数の外側と、print.c の関数の外側に gLastPrintNum の定義が登場したため、これが重複宣言と判定された訳です。このルールは、識別子(名前)に対して起こるものなので、変数でも関数でも同様です。

今回のように、別のソースファイルであっても重複宣言となってしまうのは、グローバル変数が外部結合を持つからです。

結合リンケージともいいます)とは、複数の異なる有効範囲、または1つの有効範囲内で、2つ以上の宣言が行われている識別子が、結局のところ、何を指すのかを決定することを言います。外部結合の場合は、複数ある宣言のすべてが1つの同じ定義を指すということになります。ですから、実は外部結合の宣言が複数あっても構わないのですが、定義が複数あってはならないということです。

外部結合の宣言が複数あっても構わないという部分が、今回の重複宣言を回避するポイントになります。つまり、main.c と print.c のどちらか一方の gLastPrintNum の定義を、宣言に変更すれば良いのです。

ただ、グローバル変数の宣言が、本当に宣言になるのか、定義になるのかについて、コンパイラによって細部が異なる可能性があります。確実に言えることは、明示的に初期値を与えていれば定義であるということと、extern指定子を使えば(そして初期値を与えなければ)宣言であるということです。

extern指定子は、変数を宣言する際に、型名の手前に付加します。

extern 型名 変数名;

extern を付けて宣言した変数には、定数の初期値を明示的に与えられますが、そのような変数の扱いがコンパイラ間で定まっておらず、トラブルの元なのでやめた方が無難です。

ここまでをまとめると、グローバル変数を複数のソースファイルで適切に使用するには、以下を守るようにします。

これらを踏まえて、main.c を次のように書き換えます。

/* main.c */
#include <stdio.h>
#include "print.h"

extern int gLastPrintNum;

int main(void)
{
    printNum( 100 );
    printNum( 200 );
    printNum( 300 );

    printf( "%d\n", gLastPrintNum );

    return 0;
}

実行結果:

[[ 100 ]]
[[ 200 ]]
[[ 300 ]]
300

gLastPrintNum の「定義」をしていたところに、extern を付けて、初期値を与えないようにすることで「宣言」に変更しました。こうすると、ビルドが成功して、実行結果の最後に、ちゃんと 300 が出力されます。

このような方法できちんと解決できますが、実際のところ、あまりお勧めできる方法ではありません。この方法に慣れてしまうと、プログラムがもっと大規模になったときに、どこかのソースファイルにあるたった1つの定義が、どこから参照されているのかを把握することが困難になる恐れがあります。

また、今回のサンプルプログラムでいえば、定義が書かれている print.c と、実際に使用している main.c とを結びつけているものが何もありません。唯一それらしいつながりは print.h なのですが、実のところこれがインクルードされていなくても、main.c から gLastPrintNum を使えてしまいます。

別の視点で言うと、カタログであるヘッダファイルに書かれていないはずの gLastPrintNum の定義を、main.c が勝手に使っているとも言えます。これは行儀が悪いプログラミングスタイルです。

このようなスタイルは、C言語では昔から非常によくあるやり方です。しかし、C++ を始めとした多くのプログラミング言語では、禁じ手とも言えるような悪習です。他のソースファイルに公開しても良い部分(ヘッダファイルに記述する)と、公開しない部分(ソースファイルに記述する)とをきちんと意識して分けるようにしましょう。これを意識する癖を付けておくと、他のプログラミング言語を学ぶときに非常に役立ちます。

ではどうするかというと、次のルールを守るようにします。

このルールに従って修正すると、次のようになります。

/* main.c */
#include <stdio.h>
#include "print.h"  /* ヘッダファイルにある「宣言」を使う */

int main(void)
{
    printNum( 100 );
    printNum( 200 );
    printNum( 300 );

    printf( "%d\n", gLastPrintNum );

    return 0;
}
/* print.c */
#include <stdio.h>
#include "print.h"

int gLastPrintNum = 0;  /* 唯一の「定義」 */

void printNum(int num)
{
    printf( "[[ %d ]]\n", num );
    gLastPrintNum = num;
}
/* print.h */

extern int gLastPrintNum;  /* 「宣言」 */

void printNum(int num);

実行結果:

[[ 100 ]]
[[ 200 ]]
[[ 300 ]]
300

print.c に定義があり、print.h に宣言があります。main.c は、print.h をインクルードすることによって、print.h に書かれている「宣言」を取り込んでいます。このように、ほかのソースファイルにも公開するグローバル変数を作るのなら、その「宣言」をヘッダファイルに書くようにしましょう。

C言語の範疇では、このような実装が多いですが、実はもう少し改良できます。次の項で取り上げます


なお、extern は、関数宣言にも付けられます。しかし、関数宣言は暗黙的に extern が付いているものとみなされるので、省略してしまって構いません

static と内部結合

サンプルプログラムをもう少し改良します。

グローバル変数gLastPrintNum ですが、この変数の目的は「printNum関数が、最後に出力した整数を記録しておくこと」でした。最後に出力した値であることを保証するためには、printNum関数以外の場所から、gLastPrintNum の値を書き換えることができてはいけませんし、書き換える必要性自体がないはずです。

しかし、ヘッダファイルに「宣言」を公開したため、他のソースファイルからでも gLastPrintNum にはアクセスし放題です。ヘッダファイルに公開しなくとも、最初の方法に戻って、main.c で extern したら同様に、アクセスし放題な状態になります。かといって、extern をやめると、重複宣言を避けられなくなります。

改良の鍵は、static指定子です。グローバル変数の定義に static を付加すると、結合のルールを、内部結合に変更できます。

内部結合では、1つの有効範囲内にあるすべての宣言が、たった1つの同じ定義を指します。また、定義を行ったソースファイル以外からは、その定義を使うことができなくなります。つまりは、ソースファイルの中に閉じ込めるような効果を持つということです。

static指定子が付加されたグローバル変数を使うと、次のように書けます。

/* main.c */
#include <stdio.h>
#include "print.h"

int main(void)
{
    printNum( 100 );
    printNum( 200 );
    printNum( 300 );

    printf( "%d\n", gLastPrintNum );

    return 0;
}
/* print.c */
#include <stdio.h>
#include "print.h"

static int gLastPrintNum = 0;  /* 内部結合 */

void printNum(int num)
{
    printf( "[[ %d ]]\n", num );
    gLastPrintNum = num;
}
/* print.h */

void printNum(int num);

まだコンパイルは通りません。 gLastPrintNum は内部結合を持つようになったため、定義を書いた print.c の中でしか使用できません。 ではどうするかというと、アクセスするための関数をヘッダファイルに宣言するのです。

/* main.c */
#include <stdio.h>
#include "print.h"

int main(void)
{
    printNum( 100 );
    printNum( 200 );
    printNum( 300 );

    printf( "%d\n", getLastPrintNum() );

    return 0;
}
/* print.c */
#include <stdio.h>
#include "print.h"

static int gLastPrintNum = 0;  /* 内部結合 */

void printNum(int num)
{
    printf( "[[ %d ]]\n", num );
    gLastPrintNum = num;
}

int getLastPrintNum(void)
{
    return gLastPrintNum;
}
/* print.h */

void printNum(int num);

int getLastPrintNum(void);

実行結果:

[[ 100 ]]
[[ 200 ]]
[[ 300 ]]
300

getLastPrintNum関数を追加しました。 例によって、宣言をヘッダファイルに、定義をソースファイルに記述します。 また、main.c からは gLastPrintNum を直接アクセスするのをやめて、getLastPrintNum関数を呼び出すように変更します。

変数gLastPrintNum は、内部結合になったため、print.c 以外の場所からは直接的にアクセスすることはできなくなりました。 print.c 以外のソース・ファイルからは、getLastPrintNum関数を通した、値の取得だけが許されます。

長い時間を割いて説明してきましたが、最終的な方針としては、 安易に extern を使うのはやめて、static を使おうということになります。 他のファイルから値を取得したければ、取得のための関数を用意します。 もし、値の書き換えもしたいというのならば、やはりそういう関数を用意します。


static と関数

static指定子を関数に付加すると、関数を内部結合にできます。したがって、その定義を書いたソースファイル内でしか呼び出せない関数になります。

内部結合なので、関数宣言をヘッダファイルに書いてはいけません。プロトタイプ宣言と定義は、いずれもソースファイル側に記述し、それぞれの先頭に static指定子を付けます。

次のプログラムで確認してみましょう。

/* main.c */
#include "score.h"

int main(void)
{
    printScore( 70 );
    printScore( 90 );
    printScore( 50 );
    printScore( 91 );

    return 0;
}
/* score.c */
#include <stdio.h>
#include "score.h"

static void printRank(int score);

void printScore(int score)
{
    printf( "SCORE: %d  ", score );
    printRank( score );
    printf( "\n" );
}

static void printRank(int score)
{
    printf( "RANK: " );

    if( score > 90 ){
        printf( "S" );
    }
    else if( score > 70 ){
        printf( "A" );
    }
    else if( score > 50 ){
        printf( "B" );
    }
    else{
        printf( "C" );
    }
}

/* score.h */

void printScore(int score);

実行結果:

SCORE: 70  RANK: B
SCORE: 90  RANK: A
SCORE: 50  RANK: C
SCORE: 91  RANK: S

main.c、score.c、score.h の 3つを用意します。printScore関数に、得点を渡せば、それに応じた結果を出力します。

ここで、score.c の中に、static指定子が付いた関数があります。printRank関数は、引数で受け取った得点から、ランクを決定して出力する関数です。ランクを決定する基準(例えば、ランクAとランクSの境目がどこにあるのか等)を、他のファイルにまで公開する理由がなければ、このように内部結合の関数にする価値があります。

他のファイルに判定基準を公開しないことによって、後から「今の基準では、ランクA以上になることが多すぎる」などの事情で、判定基準を変えることが簡単にできます。詳しい実装方法を「非公開」にすることの価値は、こういうところにあります。

静的ローカル変数

ここまで、static指定子をグローバル変数と関数に対して使う例を見てきました。これらはいずれも、内部結合にする効果があります。

static指定子は、ローカル変数に対して使うこともできます。static指定子を付加されたローカル変数は、静的記憶域期間を持つようになります。なお、このような変数を、静的ローカル変数と呼ぶことがあります。

ローカル変数に対する static指定子と、グローバル変数に対する static指定子は、目的がまるで異なっていることに注意して下さい。ローカル変数の場合は、静的記憶域期間にすることが目的です(ローカル変数は、そもそも他のファイルから見えないので、結合を気にしません)。グローバル変数の場合は、内部結合にすることが目的です(グローバル変数は、そもそも静的記憶域期間を持ちます)。

C++ の場合、静的ローカル変数は、その定義が実行されるときに初期化されます。初期化のタイミングがC言語とは異なることに注意が必要です。

前章でも取り上げた通り、静的記憶域期間を持つ変数に明示的に初期値を与える場合は、定数でなければなりません

静的ローカル変数は静的記憶域期間を持つので、宣言されている関数を2回以上呼び出した場合、前回の呼び出し時の値が残ったままになっています。

静的ローカル変数を使ったプログラムの例を挙げます。

#include <stdio.h>

void myprint(void);

int main(void)
{
    int i;

    for( i = 0; i < 5; ++i ){
        myprint();
    }

    return 0;
}

void myprint(void)
{
    static int num = 0;   /* プログラム開始時に作られて、ずっとそのまま */

    num += 10;            /* num はずっと記憶されるので、呼び出すたびに値は増える */
    printf( "%d\n", num );
}

実行結果:

10
20
30
40
50

myprint関数の変数num は静的ローカル変数なので、myprint関数から抜け出した後も、値が保持されたままになります。このため、実行結果にあるように、出力される値は増加していきます。


練習問題

問題① 次のプログラムの間違いを指摘して下さい。

/* main.c */
#include "sub.h"

int main(void)
{
    getString();
    putString();

    return 0;
}
/* sub.c */
#include <stdio.h>
#include "sub.h"

extern char gStr[80];


void getString()
{
    fgets( gStr, sizeof(gStr), stdin );
}

void putString()
{
    puts( gStr );
}
/* sub.h */
extern char gStr[80];

void getString();
void putString();

問題② 問題①のプログラムを、extern指定子を生かす形と、static指定子を使う形の2通りに修正して下さい。

問題③ この章の最初の方で、max関数と min関数を持った utility.c と utility.h を作成しました。 同じように、汎用的に使えそうな関数をこれらのファイルに追加し、便利な関数群を作って下さい。


解答ページはこちら

参考リンク



更新履歴

'2018/8/27 VisualStudio でヘッダファイルを作成する方法を、開発ツールのページでサポートするようにした。
VisualStudio でビルドを行う方法、実行する方法を、開発ツールのページでサポートするようにした。

'2018/7/21 static、extern をそれぞれ指定子と表記するように修正。

'2018/5/12 extern付きの変数や、静的記憶域期間を持つ変数に明示的に与える初期値が、定数でなければならないことについて追記。

'2018/4/2 「VisualC++」という表現を「VisualStudio」に統一。

'2018/2/26 全面的に文章を見直し、修正を行った。
第24章から、ビルドの流れに関する説明を移動してきて、「ビルドと実行」の項を作成。

≪更に古い更新履歴を展開する≫



前の章へ(第22章 スコープ)

次の章へ(第24章 プリプロセッサ)

C言語編のトップページへ

Programming Place Plus のトップページへ


はてなブックマーク Pocket に保存 Twitter でツイート Twitter をフォロー
Facebook でシェア Google+ で共有 LINE で送る rss1.0 取得ボタン RSS
管理者情報 プライバシーポリシー