###質問
関数のプロトタイプ宣言というのは、プロトタイプ宣言した場所よりも下なら、どこでも使えるようになるという認識で大丈夫なのでしょうか?
例えば、下記のようなソースコードをvisual studio 2017 communityで実行したところ、問題なく動作していることは確認できました。
ただ、自分の環境ではうまく動いただけの可能性があり、C言語での文法として正しいのかどうかがわかりません。
よろしくお願いします。
###ソースコード
c
1 2int test(); 3 4int main() { 5 printf("%d\n", test()); 6} 7 8int test2() { 9 return 3; 10} 11 12int test() { 13 return test2(); 14}
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答4件
0
既に解決済みですが、ちゃんと理解された方が良いと思うので。
まだ簡単なプログラムを書いておられると思いますが、これから規模が大きくなり複数のソースファイルを使ってコンパイルする様になった場合、別のソースファイルから関数 test を参照したいという事が出てくるはずです。
こういった場合プロトタイプ宣言をヘッダファイルに含ませておき、test を使うソースファイルから include します。
その際に extern という識別がある事に注意して下さい。
c:test.h
1/* test.h */ 2extern int test();
c:test.c
1/* test.c */ 2#include "test.h" 3 4...
extern はその宣言を参照するソースファイル上には test の実態は存在しないという意味になります。質問者さんのソースファイルには extern がありませんが、それは test の実態がそのソースファイルに存在するので正しい使い方です。
なおここまで書きましたが関数の場合には実は extern が付いていなくてもエラーにはなりません。つまり test が存在するソースファイルから extern が付いていない宣言を含む test.h を include してもエラーにはなりません。変数の場合には、複数のソースコード上にグローバル変数が存在する事になりリンク時にエラーとなるはずです。
これと異なり static という識別もあります。
c
1static int test();
これは逆にそのソースコード内で出現する test は、そのソースコード上でのみ有効という働きになります。ですのでヘッダファイルで切り出さずソースファイル(.c)内で宣言します。これを付けずに複数のソースファイル上で同じ関数名の実態を実装するとリンク時にエラーになります。
話を戻して、このヘッダファイルによるプロトタイプ宣言は分割コンパイル時に使われる常套手段で、Makefile と併用すると威力を発揮します。
makefile
1all : foo 2 3foo : foo.o test.o 4 gcc -Wall -o foo foo.o test.o 5 6foo.o : foo.c test.h 7 gcc -Wall -c foo.c 8 9test.o : test.c test.h 10 gcc -Wall -c test.c 11 12clean : 13 rm -f *.o 14 rm -f foo
この様に、foo.c にも test.c にも依存として test.h を含ませておくことで、関数 test に引数を足したくなった場合に未然にエラーを防げる事になります。
例えば test.h や test.c だけ修正してコンパイルすると気付かなかった foo.c の変更がエラーになってくれる訳です。
投稿2018/01/04 08:08
総合スコア5030
0
ん?
正しいですよ?
何が問題だと思ったのでしょうか?
...もしかして test2関数が test関数内で呼び出されているのに test関数のプロトタイプしかないってことでしょうか?
それなら問題ないです。
本来は載せるべきでしょうけど、
プロトタイプ宣言の効果を考えると、
( 少なくとも その関数を使う関数 ( main関数等 ) ) より前にプロトタイプ宣言か関数定義がない場合に
載せることで、「こういう関数がプロジェクト内に存在する」という情報になります。
そこから、「引数の型はこれで戻り値はこれです」っていう情報でもある。
で、プログラミングしてコンパイルするときは上から下に読み込まれる。
サンプルのやつだと、
- test関数っていうのがある。引数 void で 戻り値 int だな。
- main関数...test関数っていうのが呼び出されて その戻り値を printf関数に渡している...
- そういや、test関数っていうプロトタイプあったな...
- test2関数...
- test関数( 定義 )... test2関数を呼び出して戻り値をそのままreturnしているなぁ...
みたいな感じかな。(コンパイラを)人間だと仮定すると。
で、test2関数の定義は呼び出し側であるtest関数の前なので問題ない。
が、もしmain関数でtest2関数を呼び出そうとしているなら エラーになります。
今回は test2関数は上にあるmain関数で呼び出されていないので問題ない。
投稿2018/01/04 07:49
総合スコア4962
0
(質問へのコメントだと改行できないみたいだし、他の方の回答にぶら下げるのも何か違うような気がするのでこちらに書きます。)
質問の本筋からは外れますが、引数無しの関数の宣言や定義は
int test()
ではなく
int test(void)
にするべきだろうな、と思います。
引数を受け付けない関数の場合も必ず void を指定する
投稿2018/01/04 15:24
総合スコア366
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
認識の通りで問題ありません。
どこかでint test()
って関数実装するからみんな使ってもいいよ!
ってことです。
投稿2018/01/04 07:39
総合スコア1507
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/05 00:29
2018/01/05 01:28
2018/01/20 09:38