構造体を複数の別ファイルで使用
この記事では、C言語で扱う構造体を、複数のファイル(ソースファイル、ヘッダファイル)で使用する際の使い方について記載する。
基本的に、C言語で何かを作成する場合、1つのファイルで終わることは少ない。
複数のソースファイル、ヘッダファイルが作られる場合が多い。
特に組み込みの場合、A.cで代入した値をB.cで参照したい時がある。
今回は、それを構造体でどう行うかについて記載する。
1. 目的
・構造体を複数のファイル(ソースファイル、ヘッダファイル)で使用する際の使い方について理解する。
構造体については下記にも記載している:
・C言語基礎知識7(構造体1) - Project_OKI’s diary
・C言語基礎知識17(構造体とポインタとアロー演算子の使い方) - Project_OKI’s diary
目次
2. 構造体を複数ファイルで使用する1
※C言語基礎知識17(構造体とポインタとアロー演算子の使い方) - Project_OKI’s diary
で作成したプログラムを、複数のファイルに分けてみる。
2.1プログラムの作成1(複数ファイルの追加)
//main.cファイル #include <stdio.h> #include "main.h" #include "kannsu.h" int main(void){ Square squ; //値の入力 squ.storenum = 10; squ.beside = 10; //setNum1の実行 setNum1(squ); //squの値を表示 printf("storenum = %d\n", squ.storenum); printf("beside = %d\n", squ.beside); //setNum2の実行 setNum2(&squ); //squの値を表示 printf("storenum = %d\n", squ.storenum); printf("beside = %d\n", squ.beside); return 0; }
//main.hファイル #ifndef MAIN_H #define MAIN_H //構造体の作成 typedef struct{ int storenum; int beside; }Square; #endif
//kannsu.cファイル //ヘッダのインクルード #include "kannsu.h" //関数に構造体を渡して、データを代入 void setNum1(Square squ){ squ.storenum = 200; squ.beside = 200; } //関数に構造体のポインタを渡して、データを代入 void setNum2(Square *squ){ squ->storenum = 500; squ->beside = 500; }
#ifndef KANNSU_H #define KANNSU_H #include "main.h" //プロトタイプ宣言 void setNum1(Square squ); void setNum2(Square *squ);
#endif
実行結果:https://paiza.io/projects/nKCqijQyCblJ3SCPLyjEvw?language=c
基本的に、上記記事の内容を、
kannsu.cとkansu.hファイルを追加し、分けただけ。
2.2 プログラムの作成2(複数ファイルでグローバルとして使用する)
・上記プログラムに、Test構造体を追加し、
Test構造体をグローバルで使用する場合について記載する。
・上記プログラムでは、main関数でローカル変数として宣言し、
それを、各関数に引数として渡している。
・出来るだけ、ローカルで使用した方が良いが、実際のC言語では、グローバルで使用する場合もある。
//main.c //ヘッダファイルのインクルード #include <stdio.h> #include "kannsu.h" #include "main.h" #include "hyouzi.h" //構造体の宣言 //Test test; //グローバルでの宣言 int main(void){ Square squ; // Test test; //ローカルでの宣言 //初期値の入力 squ.storenum = 10; squ.beside = 10; test.test1 = 0; test.test2 = 0; setNum1(squ); //squデータ格納 squDisp(squ); //squデータ表示 setNum2(&squ); //squデータ格納 squDisp(squ); ///squデータ表示 setTest1(); //testデータの格納 testDisp(); //testデータの表示 printf("test.test1=%d\n",test.test1); return 0; }
//main.hファイル #ifndef MAIN_H #define MAIN_H //構造体の作成 //ローカル用構造体 typedef struct{ int storenum; int beside; }Square; //グローバル用構造体 typedef struct{ int test1; int test2; }Test; //構造体の変数定義 //extern Square squ; //ローカルで使用:無くてもエラーにならない。 extern Test test; //グローバルで使用:ないとエラーになる。 #endif
//kannsu.cファイル #include "kannsu.h" #include "main.h" //構造体の宣言 //Test test; //構造体(Square)代入用関数 void setNum1(Square squ){ squ.storenum = 200; squ.beside = 200; } //構造体に構造体のポインタを渡して計算 void setNum2(Square *squ){ squ->storenum = 500; squ->beside = 500; } //構造体(Test)代入用関数 void setTest1(){ test.test1 = 10; test.test2 = 20; }
//kannsu.hファイル #ifndef KANNSU_H #define KANNSU_H #include "main.h" //プロトタイプ宣言 void setNum1(Square squ); void setNum2(Square *squ); void setTest1(); #endif
//hyouzi.cファイル #include <stdio.h> #include "hyouzi.h" //構造体の宣言(グローバル宣言) Test test; //squデータを表示する関数 void squDisp(Square squ){ printf("storenum = %d\n", squ.storenum); printf("beside = %d\n", squ.beside); } //testデータを表示する関数 void testDisp(){ printf("test.test1 = %d\n", test.test1); printf("test.test2 = %d\n", test.test2); }
//hyouzi.hファイル #ifndef HYOUZI_H #define HYOUZI_H #include "main.h" //プロトタイプ宣言 void squDisp(Square squ); void testDisp(); #endif
実行結果:https://paiza.io/projects/V3AWV3KlaCDVcHINDlyWBA?language=c
2.3 プログラムの説明
(a) このプログラムは、メイン関数の最初でSquare及びTest構造体の初期化を行い、
setNum1、setNum2、setTest1で
構造体のデータを格納している。
squDisp、testDispで
構造体に格納されている値をprintfで出力している。
(b) //Test test; //グローバルでの宣言
Test構造体は、グローバルとして宣言されている。
このプログラムでは、main.c、kannsu.cファイルでは、
コメントアウトされており、hyouzi.cのみでグローバル変数宣言がされている。
グローバルで宣言した場合は、
hyouzi.cで宣言しても、main.cで宣言しても、kannsuで宣言しても、
どこでもよい。
コメントアウトを外して、全てに記載しても問題はない。
逆に言えば、ファイルが多くなるほど、構造体をグローバルで宣言した時、
意図しない部分で数値が変わってしまったりする可能性があり、管理が難しくなるため、注意が必要。
(c) // Test test; //ローカルでの宣言
このコメントアウトを外すと、グローバルで宣言されているTest構造体とは別に、
ローカルでTest構造体が宣言される。
その場合、メイン関数で出力している printf("test.test1=%d\n",test.test1);
のtest.test1の値は、グローバルの影響を受けず、0になる。
(d) extern Test test;
グローバルで複数のファイルで使用する場合、同じ変数ということで、
extern宣言をする必要がある。
→extern宣言については下記を参照
・C言語基礎知識10(extern宣言) - Project_OKI’s diary
関連記事
C言語:
・組み込みの為のC言語基礎知識1(printf) - Project_OKI’s diary
・C言語基礎知識2(for分で処理を繰り返す) - Project_OKI’s diary
・C言語基礎知識3(配列) - Project_OKI’s diary
・知らないと損するお金の話(ふるさと納税、確定申告とワンストップ納税どっちが得?) - Project_OKI’s diary
・C言語基礎知識6(関数) - Project_OKI’s diary
・C言語基礎知識7(構造体1) - Project_OKI’s diary
・C言語基礎知識8(enum:列挙型) - Project_OKI’s diary
・C言語基礎知識9(typedef) - Project_OKI’s diary