![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
はじめまして。
【苦しんで覚える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の場合の両方について、コンパイラがどのような順番でプログラムを処理しているのかを具体的に教えてください。
どうかよろしくお願い致します。
No.4ベストアンサー
- 回答日時:
たぶん、この例のmain()は
int main(void)
{
sum();
return 0;
}
の間違いなのでしょうか。質問に書いてある通りでは、なにもしない関数になってしまいますから。
で、質問の答えですが、
「C言語では、main()は最後に書くのがルールです。」
の一言で済ませてしまってもよかったのですが、このサイトでは、もう少しそれらしい説明をしているのでしょう。
Cコンパイラは、それほど何度もパスを繰り返していません。なので、
「使う前に定義を書かないといけない」
というのが原則になっています。main() の中で使う前に、sum()の定義が必要なのです。
本気で勉強するなら、サイトでなく、本を買ったほうがよいですよ。
早速ご回答いただき、ありがとうございました。
例題が間違っており、すみませんでした(例題1・例題2ともに実行されないプログラムを載せてしまいました)。
また、関連する新しい疑問も出てきました。
頭を整理してから再度質問をし直します。
No.5
- 回答日時:
これはC言語の仕様です。
使用する変数や関数は先に定義または宣言する必要があります。コンパイルを少しでも早くするため(今から考えると当時のミニコンは遅かった)構文解析を1Passにしたのだと思います。アセンブラ言語は普通2Passで解析します。後から出てきたシンボルがUndefineになる事はありません。
コンパイラ言語の構文解析は先頭から順に行います。解析結果はグラフ/ツリーのような形で表現されるらしいです。
早速ご回答いただき、ありがとうございました。
例題が間違っており、すみませんでした(例題1・例題2ともに何も実行しないプログラムを載せてしまいました)。
また、関連する新しい疑問も出てきました。
頭を整理してから再度質問をし直します。
No.3
- 回答日時:
まず、ここで書かれた例ではsum()をどこからも呼び出されていないのでどちらでも実行されません。
>main関数を解析している段階では、sum関数は発見されておらず、従って、main関数の中では、sum関数を使うことは出来なくなってしまいます。
この解説は間違い、後述の関数を使用出来ないのはCの言語仕様です。(出来ないと決めているから出来ない)
コンパイラは頭から逐一翻訳していくのではありません。
コンパイラによって違いますが通常は数回から十数回のパスをへてオブジェクトファイルを出力します。
具体的にコンパイラがどのような解析をしているかは簡単には書けませんから専門書を参照してください。
なぜそのような仕様になっているかですが恐らくCの開発当時のコンピュータの演算能力や使用料の低減のために人間への負担を増やすことで少しでもコンパイラを簡易なものにするためでしょう。
早速ご回答いただき、ありがとうございました。
例題が間違っており、すみませんでした(例題1・例題2ともに実行されないプログラムを載せてしまいました)。
また、関連する新しい疑問も出てきました。
頭を整理してから再度質問をし直します。
No.2
- 回答日時:
例題があまり良くないですねぇ。
>コンパイラがどのような順番でプログラムを処理しているのか
プログラムを処理…ではなく、構文解析…というべきでしょうかね。
とりあえず、プリプロセスで疑似命令とか処理して1つのファイルとして、先頭から構文解析を進めているハズです。
ちなみに、例題1も例題2もsum()はコールされていませんからどっちも「実質なにもしないmain()」が実行されるだけ…ですよ。
どっちもmain()が
int main(void)
{
sum();
return 0;
}
だった場合、
例題1だとsum()の情報(引数の数や型、戻り値の型などの情報)が無い為、コンパイルエラーか警告となります。
# そういう場合の規定があった…かと。(引数、戻り値もint型とする…でしたかね)
例題2だとmain()からsum()をコールする時にはsum()の情報は解釈済みですのでコンパイルエラーや警告になることはありません。
# もちろん、正しく使っている場合に限りますが。
つまり、呼び出す前に呼び出し先の情報があればいい。
ということになります。
main()からfunc1()をコールしているからfunc1()をmain()より前に書けばいい。
func1()からfunc2()とfunc3()とfunc4()をコールしているからfunc1()の前にfunc2()とfunc3()とfunc4()をfunc1()より前に……とかやっていけば万事解決です。
そういう依存関係を考慮してソースを書く必要がある。ってことですね。
依存関係の結果入れ子になったらどうしましょうか。
func2()からfunc3()とfunc4()をコールしている。func3()からはfunc4()をコールしている。func4()からは条件によってはfunc3()をコールすることもある。
さて、どうしましょう?
そんな依存関係も把握して書かないといけないなんて面倒ですね……。
ってことでプロトタイプ宣言ってものがあるんです。
早速ご回答いただき、ありがとうございました。
例題が間違っており、すみませんでした(例題1・例題2ともに実行されないプログラムを載せてしまいました)。
また、関連する新しい疑問も出てきました。
頭を整理してから再度質問をし直します。
No.1
- 回答日時:
先頭から順に解析しています。
例えば、変数で考えてみます。
main関数の中で
int main(void)
{
i++;
int i;
}
こうだと、エラーが出ます。変数の定義の前に変数を使用しているからです。
この場合、使用する前に必ず変数を定義する必要があります。
int main(void)
{
int i;
i++;
}
同様に、関数も定義するまえに使用してはいけないのです。ですからmainの前にプロトタイプ宣言するか、実態そのものを定義しておくか、プリプロセッサ(#include)で読み込んでおくかの必要があります。
早速ご回答いただき、ありがとうございました。
例題が間違っており、すみませんでした(例題1・例題2ともに実行されないプログラムを載せてしまいました)。
また、関連する新しい疑問も出てきました。
頭を整理してから再度質問をし直します。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語階乗の総和を求める 2 2023/03/04 23:31
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 malloc関数を使ってください!お願いします! 最 1 2022/07/21 09:28
- C言語・C++・C# 至急お願いします。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分母 3 2022/07/19 17:09
- C言語・C++・C# 至急教えてください!プログラミングの問題です。 割られる整数と割る整数を受け取って、商と余りを出力す 3 2022/07/05 10:23
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# このプログラミングの問題を教えてほしいです。 キーボードからデータ数nとn個のデータを入力し、平均値 3 2022/12/19 22:51
- C言語・C++・C# プログラミング実行後の表示される値を答えよ #include<stdio.h> void main( 7 2022/05/20 00:07
- C言語・C++・C# 至急教えてください! プログラミングの問題です! お願いします! 出力2と全く同じ出力をするように、 2 2022/06/22 23:10
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
プログラミングって右脳よりの...
-
C言語の規格
-
<conio.h>?
-
書籍「C言語逆引き大全 500の極...
-
リリースモードとデバッグモー...
-
パーサとコンパイラの違いって?
-
DOSの文字の色を変える方法。
-
Visual Studio でmakefileを使...
-
python エラー
-
エクセルのエラーメッセージ「4...
-
アプリケーションのDLLファイル...
-
<unistd.h>をVisualStudioでつ...
-
Excel VBAのCSVファイルマージ...
-
visual studio 2008 のデバッグ...
-
res://ieframe.dll/について
-
” OS ビルド ” の意味が分か...
-
gccを使ってのリンク時のライブ...
-
VB.netを実行するとデバック プ...
-
左側がクラス、構造体、共用体...
-
MinGWのg++で分割コンパイルエラー
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
unsigned long long 型のフォー...
-
ソフトの開発言語を調べる方法
-
cc と gcc の違い
-
printfなど、標準関数のソース...
-
パーサとコンパイラの違いって?
-
COBOLのALPHABET...
-
Visual Studio でmakefileを使...
-
組み込みソフト。ROM領域にデータ
-
リリースモードとデバッグモー...
-
C++Builder → Visual C++ 移植...
-
C++でデスクトップGUIアプリ開...
-
サイクルカウントの方法
-
VisualC++6.0でのProfessionalE...
-
COBOLの論理演算子について質問...
-
関数形式マクロ dtaは戻り値が...
-
C言語の2進数表記
-
POWERCOBOLのSQL...
-
Σの計算について
-
C言語の規格
-
COBOL計算式の中間ワーク桁数に...
おすすめ情報