C言語の分割ファイル先の関数呼び出しについての問題点と改善点

このQ&Aのポイント
  • C言語でファイルを関数ごとに分割した場合の関数呼び出しについての問題点と改善点を紹介します。
  • 通常、関数を呼び出す際にはプロトタイプ宣言を使用しますが、分割ファイルの場合はどのように宣言すれば良いのでしょうか。
  • include文を使用する方法もありますが、一般的には別の方法が推奨されます。
回答を見る
  • ベストアンサー

C言語で分割ファイル先の関数を呼び出す時

いつもお世話になっております. C言語の関数の呼び出しについて質問があります. main文と同じファイルにある関数は,main文より上に記述している場合は プロトタイプ宣言で呼び出すことが出来ますが,ファイルを関数ごとに分割した場合はどうしたら良いのでしょうか? 例えば main_file.c と function_file.c という2つのファイルがあり, それぞれ main と function という関数を持っているとします. main文からfunction関数を呼び出したい場合, 私はいつも main_file.c 内で include "function_file.c" としていますが, これが一般的な方法なのでしょうか? 問題点や改善点を挙げて頂けると助かります. よろしくお願い致します.

質問者が選んだベストアンサー

  • ベストアンサー
  • u-bot
  • ベストアンサー率58% (1736/2988)
回答No.2

自分はfunction関数を含む静的オブジェクトもしくはライブラリを作成します。 main関数に外部関数を定義したヘッダファイルをincludeさせてビルドします。 そしてファイルが正常にコンパイルとリンクがされるようにプロジェクトを作成します。 ------------- ファイルがメインとそれ以外の二つだけなら質問のような方法でもとりあえずは動きます。 しかし関数呼び出しとファイル構成が複雑になると面倒になります。 例えばファイルがメインと関数1、関数2、関数12の4個あり、  main -- fun1 -- fun12  ......+ fun2 -- fun12 のようにmainからfun1とfun2がコールされ、fun1とfun2の両方でfun12をコールしたとします。 includeを利用するとmain文の前にfun12、fun1、fun2の順番でincludeする必要があります。 ファイルと関数がさらに増えたらincludeの順番を注意する手間が増大します。 そういう面倒な処理はコンピュータ(コンパイル環境)にまかせるべきで、人間は正しい関数定義をmainに教えるだけにすべきです。 他に考えられる問題点としてincludeしたファイル内にあるdefineやincludeによってはinclude先の関数になにかしら影響を与える可能性があります。 例えばincludeしたファイル内で「#define TRUE 0」としていて他のファイルでは「#define TRUE 1」としていたら二重定義でコンパイルエラーになります。 コンパイルエラーや問題になったら処理を見直せばいい話ではありません。 コンパイルエラーや他の関数の処理に影響を与えないようファイルや関数は独立するように適切な記述をし、環境を構築して下さい。 ファイルや関数がきちんと独立していればそれらは他のプログラムでもそのままの形で流用できます。 流用できないのであればファイルや関数を独立させる意味が半減してしまいます。

Goe-Mon
質問者

お礼

返事が遅れてしまい,大変申し訳ありません. 回答ありがとうございます. >includeを利用するとmain文の前にfun12、fun1、fun2の順番でincludeする必要があります。 なるほど. "fun1とfun2の両方でfun12をコール"する場合,fun12が先に書かれている(コンパイルされている)必要があるのですね. また,定義の問題もなるほどと思いました. 本当に勉強になりました. ありがとうございました^^

その他の回答 (3)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

> main文と同じファイルにある関数は,main文より上に記述している場合は > プロトタイプ宣言で呼び出すことが出来ますが すみません。 質問を一通り読むと、思いちがいがあるような気がして。 「プロトタイプ宣言」と「関数の定義」はちゃんと使いわけていますか? プロトタイプ宣言は、関数の戻り値や引数の型等だけを宣言するものです。 int function(int a,int b) { functionの内容 } という関数の定義だったら、プロトタイプ宣言は int function(int a,int b) ; となります。 プロトタイプ宣言は、その関数を使用する前にする必要があります。 プロトタイプ宣言されていたら、関数の定義は、ファイルの最後でも、別ファイルでもかまいません。 関数の定義はプロトタイプ宣言も兼ねているので、使用する前に関数の定義があれば、単独のプロトタイプ宣言は無くてもいいです。 例1:プロトタイプ宣言の使用 /* functionのプロトタイプ */ int function(int,int) ; /* 変数名は省略可能 */ /* functionを使用する関数function2の定義 */ int function2(int c,int d) { .... ret=funtion(c,d); .. } /* functionの定義 */ int function(int x,int y) { /* プロトタイプと引数の数と型、戻り値の型があってれば、引数の名前は変更可能 */ .... } 例2: 先に関数を定義 /* functionのプロトタイプ */ /* int function(int,int) ; */ /* あってもなくてもよい*/ /* functionの定義 */ int function(int x,int y) { .... } /* functionを使用する関数function2の定義 */ int function2(int c,int d) { .... ret=funtion(c,d); .. } /* なお、「main『文』」ではありません。「main『関数』の定義」です main関数は、実行時に最初に呼ばれる、ということ以外は他の関数と同じです。 */ 常套手段は次の通り ・共通する関数のプロトタイプをヘッダファイルとしてまとめる。 ・ソースファイルで #include "上記ヘッダファイル" として、宣言を組込む ・分割コンパイル→リンクで実行ファイルに 実は、あなたは「別ファイルで定義されている関数を利用する」というのを、C言語の現況の最初のころから使っているはずです。 「おまじない」として #include <stdio.h> 等としているかと思います。 この stdio.h というが、ヘッダファイルです。その中身はプロトタイプ宣言が中心です。 printf等の関数は、別ファイルに書かれて、予めコンパイルしておいたものが使われます。

Goe-Mon
質問者

お礼

返事が遅れてしまい,大変申し訳ありません. 回答ありがとうございます. >なお、「main『文』」ではありません。「main『関数』の定義」です すみません. 仰る通り,main『関数』ですね. よく間違えます.おそらく,学校で先生が「main文」と言っていたからだと思います(笑) >常套手段は次の通り ・共通する関数のプロトタイプをヘッダファイルとしてまとめる。 ・ソースファイルで #include "上記ヘッダファイル" として、宣言を組込む ・分割コンパイル→リンクで実行ファイルに 丁寧にありがとうございます. 大変勉強になりました. また,質問文で迷わしてしまったようで申し訳ありません. 「プロトタイプ宣言」と「関数の定義」は使い分けているつもりですが,回答の文を読ませて頂いて,改めて整理され勉強になりました. ありがとうございました.

  • php504
  • ベストアンサー率42% (926/2160)
回答No.3

プログラムでprintf( )関数とか使いますよね どこにも定義してないのになぜ使えるのでしょう printfは標準関数だから特別というわけではありません これはstdio.hというヘッダをincludeしているからです 自作関数の場合も同様にヘッダファイルにプロトタイプ宣言を書いてincludeするのが一般的です -----function_file.h int function( int a, int b); -----function_file.c int function( int a, int b) { return a + b; } -----main_file.c #include "function_file.h" int main(void) { int c; c = function( 1, 2); . . . あとこの場合は出来たオブジェクトファイルをリンクしないといけません

Goe-Mon
質問者

お礼

返事が遅れてしまい,大変申し訳ありません. 回答ありがとうございます. >自作関数の場合も同様にヘッダファイルにプロトタイプ宣言を書いてincludeするのが一般的です 学校では「stdio.hはおまじないだから気にしないで~」という話が最初にあり, 自作関数を作ったら「プログラムの最初にプロトタイプ宣言というものを書けばmain関数を前にもってこれて綺麗に書けるよ~」とかこういう風に習いました. 今,やっと僕の中でヘッダファイルの位置付けがはっきりした気がします. 初めから「ヘッダファイルにプロトタイプ宣言を書いて」と教えてくれればいいのにと思いました(笑) ありがとうございました.

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

プロトタイプ宣言を書いたヘッダファイルを作って #include, 最後にリンク が「一般的」でしょうな.

Goe-Mon
質問者

お礼

返事が遅れてしまい,大変申し訳ありません. 回答ありがとうございます. 勉強になりました.

関連するQ&A

  • ソースファイルの分割

    自分で作成したプログラムが長くなってしまったのでいくつかのファイルに分割したいのですが、一般にはどのように分けるのでしょうか? 作成したプログラムは以下のような内容を含んでいます。 クラス  クラスの定義  メンバ関数の定義 関数×2  定義  プロトタイプ宣言 main関数 プリプロセッサ制御文も教えてくださると助かります。

  • JNAでc言語ファイルの読み込み方が分かりません

    JNAでc言語ファイルの読み込み方が分かりません JNAを使用して、javaからcを読み込み動作するプログラムを作っています。 なんとなく定義は分かってきたのですが、 javaのソースコードに CLibrary.INSTANCE.printf(); のように、c言語を書き込んでいる状況なのですが、 JNAを利用した.javaファイルから.cファイルを読み込む方法はありますか? c言語の場合、.cファイルごとに分割された関数をmainが呼び出すとき、 extern void Sample(); とプロトタイプ宣言の後に Sample(); で呼び出せるみたいなので、 これを使って、 CLibrary.INSTANCE.extern void Sample(); とやってみましたが、コンパイルできませんでした;; 他にやり方がありますか? 知ってる方がいらっしゃいましたら、教えてください。 よろしくお願いします。

    • ベストアンサー
    • Java
  • Borland C++ Compiler 5.5でland関数がコンパイルできません

    初歩的な質問ですみません。C言語のプログラミングの質問です。 タイトルどおり、Borland C++ Compiler 5.5でland関数がコンパイルできません。OSはWindows XPで、「c言語を始めよう!」を使ってプログラムを作っています。 今まで学校でunixを使っていたので、その時は何の設定もせずに使えたので普通に使ったのですが、”プロトタイプ宣言のない関数 'rand' の呼び出し”や”プロトタイプ宣言のない関数 'srand' の呼び出し”というエラーが出ます。 timeを使うために#include <time.h>が必要だったり、そのようなunixでは不必要だった下準備が必要なのでしょうか?

  • C++のファイル分割でのエラーについて

    最近VC2008でC++の勉強を始めたのですが、ファイル分割でLNK2005エラーというのが発生し、解消できません。 インクルードガードは行ったのですが、どうしたらよいのか分かりません。 ソースコードはこんな感じです。 //main.cpp #include "sub.h" #include "res.h" bool main(){ calcx(m_x); calcy(m_y); } //res.h 共有変数の宣言 #ifndef __RES_H #define __RES_H int m_x; int m_y; #endif //sub.h 関数のプロトタイプ宣言を行う void calcx(); void calcy(); //sub.cpp 関数の定義を記述する #include "res.h" void calcx(int x){ m_x = x + 100; } void calcy(int y){ m_y = y + 200; } エラー: 1>Main.obj : error LNK2005: "int m_x" (?m_x@@3HA) は既に sub.obj で定義されています。 1>Main.obj : error LNK2005: "int m_y" (?m_y@@3HA) は既に sub.obj で定義されています。 上記のようなエラーを解消するにはどうしたら良いのでしょうか。 何がおかしいのか指摘をお願いします。

  • どなたか、教えていただけませんでしょうか(C言語)?

    皆様のお知恵を拝借したく思いまして 投稿させていただきました C言語についての質問なのですが (1)文字配列の引数を一度mainからプロトタイプ関数へ渡し 関数で宣言して表示。 (2)さらにその関数内で、値を変更して mainで表示する 方法を教えていただきたく思いますので、宜しくお願い致します

  • C言語 関数について

    協力お願いします。 2問あります。 1問目です。 西暦年yearを引数として受け取り, 閏年かどうかの判定結果を戻り値として返す関数leap_year()を作成せよ. ただし,leap_year()は,閏年の場合は1を返し, そうでない場合は0を戻り値として返すものとする. 提出するプログラムは,関数leap_year()だけでなく, メイン関数main()も含む下記プログラムを完成させる形で作成する。 #include <stdio.h> /* ここに関数leap_year()のプロトタイプ宣言を記述する */ int main() { int i, year[3]; for (i=0; i<3; i++) { printf("西暦年を入力してください"); scanf("%d", &year[i]); if (leap_year(year[i]) == 1) { printf("閏年です.\n"); } else { printf("閏年ではありません.\n"); } } } /* ここに関数leap_year()を定義する */ 2問目です。 mのn乗を計算する関数power()を作成せよ. ただし,関数power()はm,nを引数とし, 戻り値としてmのn乗の値を返すものとする. m,nは,正整数とする.プログラムには, 関数power()だけでなく,m,nを入力し, mのn乗を出力するメイン関数main()を含むものとする. main()は,power()の前に記述すること. また,power()のプロトタイプ宣言も記述すること。 よろしくお願いします。

  • 複数ファイルに分割した時の構成について

    大学の卒論にむけてプログラムを書いていて、一つのmain.cでは長くなってきたので、関数を func1.h func1.c のような別ファイルに記述することにしました。 その現在の構成を、質問欄の下部に簡単に書いたので、構成が自然かどうか意見をお聞きしたいです。特に、 「include文、define文をヘッダファイルにまとめて、各ファイルからincludeしている構造」がコードの記述方法として、きもちわるくないか、一般的かどうか、教えてください。 このようにした理由は、 ・defineマクロを多くのサブ関数で利用している。 ・define定義の値を細かく変えながら実行し、結果の違いを出力したい。 ・その為、各ファイルの頭にdefine定義を置いた場合、定義の値を  いちいち全てのファイルで変更しなければならなくなり、面倒…。 →defineマクロをdefine.hにまとめた。ついでに、<stdio.h>,<math.h>なども置いてしまえばスッキリするかも~。 という経緯です。 理学の学科でまわりに詳しい人がいなく、 プログラム知識もほぼ独学なので、不安に感じて質問しました。 よろしくおねがいします。 +++++++++++++ 以下が、簡単なファイル構成です +++++++++++++ -----define.h----- #include <stdio.h> #include <math.h> #define A_MAX 3 #define B_MAX 5 -----main.c---- #include "define.h" int main() { func1(); func2(); func3(); } -----func1.h---- #include "define.h" void func1(int hoge); //プロトタイプ宣言 -----func1.c---- #include "func1.h" void func1() { hogehoge; } ------func2以下、func1と同構造

  • C言語 main関数とsum関数の記述順について

    はじめまして。 【苦しんで覚えるC言語】(Web版)でC言語を学んでいる初学者です。 【第1部:C言語基礎編】>【関数の作り方】>【自作関数を作る】の部分(http://9cguide.appspot.com/11-01.html#S2)でつまづいています。 下記のような、1から100までの数字の合計を表示するプログラムが例題として取り上げられています。 しかし、ここが理解できないので、次の【プロトタイプ宣言】に進めずにいます。 例題1  sum関数をmain関数の後に記述した場合(プログラムが実行されない)。 #include <stdio.h> int main(void) { return 0; } int sum(void) { printf("%d\n",(1 + 100) * 100 / 2); return 0; } 例題2  sum関数をmain関数の先に記述した場合(プログラムが実行される)。 #include <stdio.h> int sum(void) { printf("%d\n",(1 + 100) * 100 / 2); return 0; } int main(void) { return 0; } 例題1の場合、【まずmain関数を作り、次にsum関数を作りました。この場合、main関数を解析している段階では、sum関数は発見されておらず、従って、main関数の中では、sum関数を使うことは出来なくなってしまいます。】との説明がありますが理解できません。 コンパイラがどのような順番でプログラムを処理しているか理解できていないので分からないのだと思います。 例題1の場合と例題2の場合の両方について、コンパイラがどのような順番でプログラムを処理しているのかを具体的に教えてください。 どうかよろしくお願い致します。

  • C++のコンパイルエラーが

    おこります。 --------------------------------- #include <stdio.h> int main(void) { printf("hello, world\n"); return 0; } -------------------------------------- をコンパイルするのですができません。 以下のエラーが出ます。 --------------------------------------- エラー E2209 sample.c 1: インクルードファイル 'stdio.h' をオープンできない 警告 W8065 sample.c 5: プロトタイプ宣言のない関数 'printf' の呼び出し(関数 main ) *** 1 errors in Compile *** -------------------------------------

  • C言語で、記憶クラス指定子extern・staticを関数に指定

    C言語の本に、「関数の定義と呼び出す側が別ソースファイルの場合、プロトタイプはヘッダーファイルに書き、定義側と呼び出し側の両方でインクルードしましょう」ということが書かれていました。 例えば、 ===code1a.c=== extern void funcB(int); static void funcA() { funcB(1); } ===code1b.c=== void funcB(int a) { printf("%d\n",a); } このような場合には、もしcode1b.cの中の関数funcBに引数を追加した場合、再コンパイルしても気づかないのでよくない。 そこで、次のようにヘッダーファイルを作り、プロトタイプはそこに書くべきだ。 ***code2b.h*** extern void funcB(int); ***code2a.c*** #include "code2b.h" static void funcA() { funcB(1); } ******code2b.c**** #include "code2b.h" void funcB(int a) { printf("%d\n",a); } 記述は以上のようなことです。 #include "code2b.h" とは、 extern void funcB(int); が書いてあるのと同じだと思います。 私が思ったのは、本の勧める方法では、 funcBを定義しているcode2b.cで、プロトタイプの記憶クラス指定子が、externになっているが良いのか(externとは、別のソースファイルで定義されているという意味ではないか)ということです。 extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。 私の処理系では、 ・プロトタイプ宣言でexternを付けて関数定義でstaticを付ける、 ・staticを付けた関数を他のソースファイルで呼ぶ、 などの明らかに矛盾する場合は、コンパイルエラーになります。 でも、extern単独での役割はなさそうです。 他の処理系でも同じでしょうか。 (main等省略)

専門家に質問してみよう