こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C言語で、記憶クラス指定子extern・staticを関数に指定

C言語の本に、「関数の定義と呼び出す側が別ソースファイルの場合、プロトタイプはヘッダーファイルに書き、定義側と呼び出し側の両方でインクルードしましょう」ということが書かれていました。

例えば、
===code1a.c===
extern void funcB(int);

static void funcA()
{
funcB(1);
}
===code1b.c===
void funcB(int a)
{
printf("%d\n",a);
}

このような場合には、もしcode1b.cの中の関数funcBに引数を追加した場合、再コンパイルしても気づかないのでよくない。

そこで、次のようにヘッダーファイルを作り、プロトタイプはそこに書くべきだ。

***code2b.h***
extern void funcB(int);

***code2a.c***
#include "code2b.h"

static void funcA()
{
funcB(1);
}
******code2b.c****
#include "code2b.h"

void funcB(int a)
{
printf("%d\n",a);
}

記述は以上のようなことです。

#include "code2b.h" とは、
extern void funcB(int);
が書いてあるのと同じだと思います。

私が思ったのは、本の勧める方法では、
funcBを定義しているcode2b.cで、プロトタイプの記憶クラス指定子が、externになっているが良いのか(externとは、別のソースファイルで定義されているという意味ではないか)ということです。

extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。

私の処理系では、
・プロトタイプ宣言でexternを付けて関数定義でstaticを付ける、
・staticを付けた関数を他のソースファイルで呼ぶ、
などの明らかに矛盾する場合は、コンパイルエラーになります。

でも、extern単独での役割はなさそうです。
他の処理系でも同じでしょうか。

(main等省略)

投稿日時 - 2002-07-27 01:05:55

QNo.323231

暇なときに回答ください

質問者が選んだベストアンサー

少々引用の順番を変えます。

> #include "code2b.h" とは、
> extern void funcB(int);
> が書いてあるのと同じだと思います。

結果としては同じですが、code2b.cにfuncB1~funcB10まで在ったとして、
code1b.c内で使うのに、code2b.hを一回includするのと
10回プロトタイプを書くのでは効率が違ってきます。


> でも、extern単独での役割はなさそうです。
> 他の処理系でも同じでしょうか。

関数に関しては、記憶クラス指定子が無いときのデフォルトが
externであるため、役割が無いと言ってしまえば無いです。
# プログラマに関数が他のファイルから呼ばれることを明示的に示して
# 注意を促すぐらいの意味です。

> funcBを定義しているcode2b.cで、プロトタイプの記憶クラス指定子が、externになっているが良いのか(externとは、別 のソースファイルで定義されているという意味ではないか)ということです。

externで宣言したからと言って、同一ファイル内に定義してはいけないという物ではないので、問題ないです。

> extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。

書くなら両方に書く、書かないなら両方とも書かないのが良いでしょう。

投稿日時 - 2002-07-27 08:11:37

補足

>externで宣言したからと言って、同一ファイル内に定義してはいけないという物ではないので、問題ないです。

わかりました。



extern,staticを書く位置について:

>書くなら両方に書く、書かないなら両方とも書かないのが良いでしょう。

staticを両方に書くということは、例えばこうですね。
(ここから)
*******code4a.c*******
#include <stdio.h>
static void funcS(int); /* プロトタイプでstatic */
extern void funcB(int);

int main(void)
{
funcS(100);
funcB(200);
return 0;
}

static void funcS(int a) /* 定義でstatic */
{
printf("A %d\n", a);
}
********code4b.c*******
#include <stdio.h>
static void funcS(int); /* プロトタイプでstatic */

void funcB(int x)
{
funcS(x);
}

static void funcS(int a) /* 定義でstatic */
{
printf("B %d\n", a);
}
(ここまで)

投稿日時 - 2002-07-28 05:37:05

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.3

関数に関してはexternの役割については既に回答がありますので省略します。
extern はむしろ変数で重要な役割を担っています。
つまり、
extern int foo;
では、外部fooは外部参照する変数という意味になり、その宣言されたモジュール内では変数領域は確保されません。
が、
int foo;
では当然そのモジュール内に変数が確保されます。
このようにexternの指定の有無により動作が異なります。

あと特殊な例としては、CとC++を共存させるために、C言語の関数に対して、
extern "C" <関数プロトタイプ宣言>
又は、
extern "C" {
<関数プロトタイプ宣言1>
<関数プロトタイプ宣言2>

}

として、C++名前規則ではなくCの規則で関数名を展開するよう指定するという特殊なものもあります。
(Cで書かれたモジュールをC++ソースから呼ぶときに必要)

通常は、Header Fileに、

#ifdef __cplusplus
extern "C" {
#endif

<関数プロトタイプ1>
<関数プロトタイプ2>
<関数プロトタイプ3>

#ifdef __cplusplus
}
#endif

とifdefを使い汎用性を持たせます。

投稿日時 - 2002-07-27 10:59:25

補足

#ifdef __cplusplus
extern "C" {
#endif

<関数プロトタイプ1>
<関数プロトタイプ2>
<関数プロトタイプ3>

#ifdef __cplusplus
}
#endif


この書き方ですが、見たことあります。
#一瞬、ひょっとしてmickjey2さまは私の身近な人物では? と思ったんですが、きっとどこでも使われているような書き方なんでしょうね。

ただ、私はC++を知らないし(C++という言語があるのは知っていますが。)。。。
まあそういうものなのかなあ、という感じです。

投稿日時 - 2002-07-28 05:56:13

お礼

ご回答の件は
C言語 FAQ 日本語訳 20.25
http://www.catnet.ne.jp/kouno/c_faq/c20.html#25
に書いてある件のことですね。

投稿日時 - 2002-07-29 22:19:09

ANo.1

>funcBを定義しているcode2b.cで、プロトタイプの記憶クラス指定子が、externになっているが良いのか

これは問題ありません。externには「全ファイル中のどこかに定義されている」というような意味合いがあります。そのため、funcBの定義されているファイルに「extern void funcB(int); 」のような宣言があっても大丈夫なはずです。

>extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。

externについてはプロトタイプにのみ書くものだと思います。定義にまで書くとなるとstatic以外の全ての関数にexternを付ける事になって面倒です。staticについては自信がないので他の方に譲ります。両方に付けておけば間違いないとは思いますが。

投稿日時 - 2002-07-27 07:23:06

補足

>funcBの定義されているファイルに「extern void funcB(int); 」のような宣言があっても大丈夫なはずです。

******code2b.c****
#include "code2b.h"

void funcB(int a)
{
printf("%d\n",a);
}

 私はexternで関数をプロトタイプ宣言したら、そのソースファイルでは関数の定義を書けないのだと誤解していました。
 変数の場合も、非常にわざとらしい例ですが、下のように宣言するのは問題ないということがわかりました。
****code3.c*****
#include <stdio.h>
extern int n; /* nをexternで宣言 */
int n=100; /* nの定義(宣言) */
int main(void)
{
printf("nは%d\n", n);
return 0;
}

>>extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。
>externについてはプロトタイプにのみ書くものだと思います。

わかりました。ありがとうございました。

投稿日時 - 2002-07-28 04:48:51

あなたにオススメの質問