いつもお世話になっております.
C言語の関数の呼び出しについて質問があります.
main文と同じファイルにある関数は,main文より上に記述している場合は
プロトタイプ宣言で呼び出すことが出来ますが,ファイルを関数ごとに分割した場合はどうしたら良いのでしょうか?
例えば main_file.c と function_file.c という2つのファイルがあり,
それぞれ main と function という関数を持っているとします.
main文からfunction関数を呼び出したい場合,
私はいつも main_file.c 内で include "function_file.c" としていますが,
これが一般的な方法なのでしょうか?
問題点や改善点を挙げて頂けると助かります.
よろしくお願い致します.
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」としていたら二重定義でコンパイルエラーになります。
コンパイルエラーや問題になったら処理を見直せばいい話ではありません。
コンパイルエラーや他の関数の処理に影響を与えないようファイルや関数は独立するように適切な記述をし、環境を構築して下さい。
ファイルや関数がきちんと独立していればそれらは他のプログラムでもそのままの形で流用できます。
流用できないのであればファイルや関数を独立させる意味が半減してしまいます。
返事が遅れてしまい,大変申し訳ありません.
回答ありがとうございます.
>includeを利用するとmain文の前にfun12、fun1、fun2の順番でincludeする必要があります。
なるほど.
"fun1とfun2の両方でfun12をコール"する場合,fun12が先に書かれている(コンパイルされている)必要があるのですね.
また,定義の問題もなるほどと思いました.
本当に勉強になりました.
ありがとうございました^^
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等の関数は、別ファイルに書かれて、予めコンパイルしておいたものが使われます。
返事が遅れてしまい,大変申し訳ありません.
回答ありがとうございます.
>なお、「main『文』」ではありません。「main『関数』の定義」です
すみません.
仰る通り,main『関数』ですね.
よく間違えます.おそらく,学校で先生が「main文」と言っていたからだと思います(笑)
>常套手段は次の通り
・共通する関数のプロトタイプをヘッダファイルとしてまとめる。
・ソースファイルで #include "上記ヘッダファイル" として、宣言を組込む
・分割コンパイル→リンクで実行ファイルに
丁寧にありがとうございます.
大変勉強になりました.
また,質問文で迷わしてしまったようで申し訳ありません.
「プロトタイプ宣言」と「関数の定義」は使い分けているつもりですが,回答の文を読ませて頂いて,改めて整理され勉強になりました.
ありがとうございました.
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);
.
.
.
あとこの場合は出来たオブジェクトファイルをリンクしないといけません
返事が遅れてしまい,大変申し訳ありません.
回答ありがとうございます.
>自作関数の場合も同様にヘッダファイルにプロトタイプ宣言を書いてincludeするのが一般的です
学校では「stdio.hはおまじないだから気にしないで~」という話が最初にあり,
自作関数を作ったら「プログラムの最初にプロトタイプ宣言というものを書けばmain関数を前にもってこれて綺麗に書けるよ~」とかこういう風に習いました.
今,やっと僕の中でヘッダファイルの位置付けがはっきりした気がします.
初めから「ヘッダファイルにプロトタイプ宣言を書いて」と教えてくれればいいのにと思いました(笑)
ありがとうございました.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語のwhileを含む関数について 2 2022/12/16 12:28
- C言語・C++・C# アセンブラ指令 3 2023/06/17 14:47
- C言語・C++・C# 至急教えてください!プログラミングの問題です。 割られる整数と割る整数を受け取って、商と余りを出力す 3 2022/07/05 10:23
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- その他(プログラミング・Web制作) 十進BASICでの再帰についての質問です。 2 2022/11/18 09:17
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 malloc関数を使ってください!お願いします! 最 1 2022/07/21 09:28
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
- C言語・C++・C# 至急お願いします。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分母 3 2022/07/19 17:09
- C言語・C++・C# C言語初心者 ポインタについて、お助けください、、 2 2023/03/15 23:50
- その他(プログラミング・Web制作) pythonのエラーについて 2 2022/08/17 17:17
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
DWORDの実際の型は何でしょうか
-
typedef enumの使い方を教えて...
-
long型の定数の末尾にLを付ける...
-
2重定義って??
-
visualstudio C# テキストボッ...
-
C++のfor文について
-
変数の型を定義しなかった場合...
-
C++でboolにintの値を代入する...
-
intとINTの違いは?
-
【#define】 defineで定義した...
-
main.c:7:43: warning: implici...
-
プログラムの中で別のmainを呼...
-
配列を用いない最大値の求め方
-
namespace定義の使い方
-
enumについて
-
C++の(左辺値)参照を参照渡し
-
コンパイルすると error C1083 ...
-
GCCで暗黙の型変換の警告を出し...
-
main()とint main(void)の違い
-
値を返り値に返すのと参照渡し...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
DWORDの実際の型は何でしょうか
-
typedef enumの使い方を教えて...
-
C++のfor文について
-
long型の定数の末尾にLを付ける...
-
2重定義って??
-
関数の実体定義にヘッダファイ...
-
main.c:7:43: warning: implici...
-
変数の型を定義しなかった場合...
-
visualstudio C# テキストボッ...
-
ハンドルされていない例外が発...
-
C++でboolにintの値を代入する...
-
enumについて
-
構造体の宣言でエラーが出ます。
-
【#define】 defineで定義した...
-
C++ クラスをメンバにもつクラ...
-
0除算を判定したい
-
構造体の要素すべてに対する四...
-
値を返り値に返すのと参照渡し...
-
namespace定義の使い方
-
GCCで暗黙の型変換の警告を出し...
おすすめ情報