プロが教えるわが家の防犯対策術!

いつもお世話になっております.

C言語の関数の呼び出しについて質問があります.

main文と同じファイルにある関数は,main文より上に記述している場合は
プロトタイプ宣言で呼び出すことが出来ますが,ファイルを関数ごとに分割した場合はどうしたら良いのでしょうか?

例えば main_file.c と function_file.c という2つのファイルがあり,
それぞれ main と function という関数を持っているとします.

main文からfunction関数を呼び出したい場合,
私はいつも main_file.c 内で include "function_file.c" としていますが,
これが一般的な方法なのでしょうか?

問題点や改善点を挙げて頂けると助かります.

よろしくお願い致します.

A 回答 (4件)

自分は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」としていたら二重定義でコンパイルエラーになります。
コンパイルエラーや問題になったら処理を見直せばいい話ではありません。
コンパイルエラーや他の関数の処理に影響を与えないようファイルや関数は独立するように適切な記述をし、環境を構築して下さい。

ファイルや関数がきちんと独立していればそれらは他のプログラムでもそのままの形で流用できます。
流用できないのであればファイルや関数を独立させる意味が半減してしまいます。
    • good
    • 0
この回答へのお礼

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

>includeを利用するとmain文の前にfun12、fun1、fun2の順番でincludeする必要があります。
なるほど.
"fun1とfun2の両方でfun12をコール"する場合,fun12が先に書かれている(コンパイルされている)必要があるのですね.

また,定義の問題もなるほどと思いました.

本当に勉強になりました.
ありがとうございました^^

お礼日時:2011/01/12 23:57

> 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等の関数は、別ファイルに書かれて、予めコンパイルしておいたものが使われます。
    • good
    • 0
この回答へのお礼

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

>なお、「main『文』」ではありません。「main『関数』の定義」です
すみません.
仰る通り,main『関数』ですね.
よく間違えます.おそらく,学校で先生が「main文」と言っていたからだと思います(笑)


>常套手段は次の通り
・共通する関数のプロトタイプをヘッダファイルとしてまとめる。
・ソースファイルで #include "上記ヘッダファイル" として、宣言を組込む
・分割コンパイル→リンクで実行ファイルに

丁寧にありがとうございます.
大変勉強になりました.

また,質問文で迷わしてしまったようで申し訳ありません.
「プロトタイプ宣言」と「関数の定義」は使い分けているつもりですが,回答の文を読ませて頂いて,改めて整理され勉強になりました.

ありがとうございました.

お礼日時:2011/01/13 00:16

プログラムで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);
.
.
.

あとこの場合は出来たオブジェクトファイルをリンクしないといけません
    • good
    • 0
この回答へのお礼

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

>自作関数の場合も同様にヘッダファイルにプロトタイプ宣言を書いてincludeするのが一般的です

学校では「stdio.hはおまじないだから気にしないで~」という話が最初にあり,
自作関数を作ったら「プログラムの最初にプロトタイプ宣言というものを書けばmain関数を前にもってこれて綺麗に書けるよ~」とかこういう風に習いました.

今,やっと僕の中でヘッダファイルの位置付けがはっきりした気がします.

初めから「ヘッダファイルにプロトタイプ宣言を書いて」と教えてくれればいいのにと思いました(笑)

ありがとうございました.

お礼日時:2011/01/13 00:08

プロトタイプ宣言を書いたヘッダファイルを作って #include, 最後にリンク


が「一般的」でしょうな.
    • good
    • 0
この回答へのお礼

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

勉強になりました.

お礼日時:2011/01/12 23:50

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!