質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.83%

  • C

    3347questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • 関数

    193questions

    関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

C言語での関数のプロトタイプ宣言について

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 378

2lu3

score 7

質問

関数のプロトタイプ宣言というのは、プロトタイプ宣言した場所よりも下なら、どこでも使えるようになるという認識で大丈夫なのでしょうか?
例えば、下記のようなソースコードをvisual studio 2017 communityで実行したところ、問題なく動作していることは確認できました。
ただ、自分の環境ではうまく動いただけの可能性があり、C言語での文法として正しいのかどうかがわかりません。

よろしくお願いします。

ソースコード

int test();

int main() {
    printf("%d\n", test());
}

int test2() {
    return 3;
}

int test() {
    return test2();
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+4

既に解決済みですが、ちゃんと理解された方が良いと思うので。

まだ簡単なプログラムを書いておられると思いますが、これから規模が大きくなり複数のソースファイルを使ってコンパイルする様になった場合、別のソースファイルから関数 test を参照したいという事が出てくるはずです。

こういった場合プロトタイプ宣言をヘッダファイルに含ませておき、test を使うソースファイルから include します。

その際に extern という識別がある事に注意して下さい。

/* test.h */
extern int test();
/* test.c */
#include "test.h"

...

extern はその宣言を参照するソースファイル上には test の実態は存在しないという意味になります。質問者さんのソースファイルには extern がありませんが、それは test の実態がそのソースファイルに存在するので正しい使い方です。

なおここまで書きましたが関数の場合には実は extern が付いていなくてもエラーにはなりません。つまり test が存在するソースファイルから extern が付いていない宣言を含む test.h を include してもエラーにはなりません。変数の場合には、複数のソースコード上にグローバル変数が存在する事になりリンク時にエラーとなるはずです。

これと異なり static という識別もあります。

static int test();

これは逆にそのソースコード内で出現する test は、そのソースコード上でのみ有効という働きになります。ですのでヘッダファイルで切り出さずソースファイル(.c)内で宣言します。これを付けずに複数のソースファイル上で同じ関数名の実態を実装するとリンク時にエラーになります。

話を戻して、このヘッダファイルによるプロトタイプ宣言は分割コンパイル時に使われる常套手段で、Makefile と併用すると威力を発揮します。

all : foo

foo : foo.o test.o
    gcc -Wall -o foo foo.o test.o

foo.o : foo.c test.h
    gcc -Wall -c foo.c

test.o : test.c test.h
    gcc -Wall -c test.c

clean : 
    rm -f *.o
    rm -f foo

この様に、foo.c にも test.c にも依存として test.h を含ませておくことで、関数 test に引数を足したくなった場合に未然にエラーを防げる事になります。
例えば test.h や test.c だけ修正してコンパイルすると気付かなかった foo.c の変更がエラーになってくれる訳です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/05 09:29

    詳しい回答をありがとうございます。

    externなのですが、プロのプログラマはヘッダファイルの関数にexternをつけるのでしょうか?
    また、つけないことによるデメリットはあるのでしょうか?

    キャンセル

  • 2018/01/05 10:28

    人それぞれですが、僕は付けない派です。昔の OSS 等は付いている物が多いです。付けない事のデメリットは関数の場合には無いはずです。

    キャンセル

  • 2018/01/20 18:38

    ありがとうございます

    キャンセル

+2

ん?

正しいですよ?

何が問題だと思ったのでしょうか?

...もしかして test2関数が test関数内で呼び出されているのに test関数のプロトタイプしかないってことでしょうか?

それなら問題ないです。

本来は載せるべきでしょうけど、

プロトタイプ宣言の効果を考えると、

( 少なくとも その関数を使う関数 ( main関数等 ) ) より前にプロトタイプ宣言か関数定義がない場合に

載せることで、「こういう関数がプロジェクト内に存在する」という情報になります。

そこから、「引数の型はこれで戻り値はこれです」っていう情報でもある。

で、プログラミングしてコンパイルするときは上から下に読み込まれる。

サンプルのやつだと、

  1. test関数っていうのがある。引数 void で 戻り値 int だな。
  2. main関数...test関数っていうのが呼び出されて その戻り値を printf関数に渡している...
  3. そういや、test関数っていうプロトタイプあったな...
  4. test2関数...
  5. test関数( 定義 )... test2関数を呼び出して戻り値をそのままreturnしているなぁ...

みたいな感じかな。(コンパイラを)人間だと仮定すると。

で、test2関数の定義は呼び出し側であるtest関数の前なので問題ない。

が、もしmain関数でtest2関数を呼び出そうとしているなら エラーになります。

今回は test2関数は上にあるmain関数で呼び出されていないので問題ない。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/04 16:53

    わかりやすい解説を有難うございます。
    まさに、「test2関数が test関数内で呼び出されているのに test関数のプロトタイプしかない」ところが問題とならないかと思っていました。
    説明が少なくてすみません(汗。

    キャンセル

  • 2018/01/20 19:22

    無問題。test2の実装がホントに存在しないならリンク時に失敗する。

    キャンセル

checkベストアンサー

+1

認識の通りで問題ありません。

どこかでint test()って関数実装するからみんな使ってもいいよ!
ってことです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/04 16:42

    了解です。
    ありがとうございます。

    キャンセル

+1

(質問へのコメントだと改行できないみたいだし、他の方の回答にぶら下げるのも何か違うような気がするのでこちらに書きます。)
質問の本筋からは外れますが、引数無しの関数の宣言や定義は
int test()
ではなく
int test(void)
にするべきだろうな、と思います。
引数を受け付けない関数の場合も必ず void を指定する

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/05 09:27

    了解です。
    回答ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.83%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3347questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • 関数

    193questions

    関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。