• ベストアンサー

プロトタイプなのにexternを使っても良いのか?

 1999年の古いソフトを解析しているのですが、 extern の使い方に疑問が有ります。  ヘッダの中に全ての関数が extern で宣言されています。  その中に自分自身の関数も含まれていますから、プロトタイプ であるべき関数が extern になっています。  しかしエラーにはならない。  これは正当な使い方なのでしょうか。  宜しくお願いします。

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

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

アセンブラの仕様を頼りにC言語を理解しようとしているところに無理があります。 C言語には、「結合」という概念があり、オブジェクトや関数は、 1. 外部結合 2. 内部結合 3. 無結合 のどれかになります。 このうち、無結合は関数の中で定義された局所オブジェクトに適用されるものですので、関数の場合は外部結合か内部結合のどちらかになります。 extern記憶クラス指定子は外部結合を、static記憶クラス指定子は内部結合を指定するわけですが、ルネサス(というか旧日立系)のアセンブラでいうところのEXTERNやGLOBALのように、参照か定義かを表す概念ではありません。 C言語では定義も宣言の一種なのですが、関数に限っていえば、関数本体があれば定義であり、関数本体がなければ(定義ではない)単なる宣言です。externやstaticが付いていようがいまいが関係ありません。 ちなみに、関数の場合、宣言がなくても参照だけなら可能です。

richardo
質問者

お礼

有り難う御座いました

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (1)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

なぜエラーになると考えたのでしょうか? 関数の場合も宣言の一種ですから、記憶クラス指定子を伴うことはなんら問題ありません。 この辺りの厳密なことを調べたいのであれば、「プログラミング言語C」を読むより、規格書を読むことをお勧めします。

richardo
質問者

お礼

 御回答ありがとう御座います。 >なぜエラーになると考えたのでしょうか?  ルネサスH8マイコンのアセンブラでは次のようになっています。 EXP0RT :外部定義シンボルを宣言する IMPORT :外部参照シンボルを宣言する GLOBAL :外部参照シンボルまたは外部定義シンボルを宣言する  外部から自分を参照させるにはEXP0RT、外部を参照するにはIMPORT を使います。方向性が有ります。  ファイルを分割したときに共通ヘッダで IMPORT を宣言すると、 あるファイルにとっては EXP0RT のシンボルが存在します。  それを解決するのが GLOBAL です。  方向性が無いのでシンボルがファイルの内部に有るのか外部 に有るのか明確でないのが欠点です。  C言語の extern は IMPORT 相当だと思ったのですが、GLOBAL 相当だったのですね。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 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等省略)

  • C言語 extern について

    どうもこんにちは C言語でプログラムを作っています。 複数のファイルから1つのプログラムを作っていますが、あるファイルで実装した関数を別のファイルから使用する際、単にプロトタイプ宣言を行うだけでなく、extern が必要なのでしょうか? 今までは extern を使用せず、以下のように書いてました。 // main.c ファイル int func_sub(); int func_main() { return func_sub() * 2; } // sub.c ファイル int func_sub() { return 10; } これは extern を使用して、このように書かないとだめなのでしょうか? // main.c ファイル extern int func_sub(); // このexternは必要? int func_main() { return func_sub() * 2; } // sub.c ファイル int func_sub() { return 10; } 大域変数を他のファイルでも使用する場合はexternが必要ですが、関数に関してもexternを使用しなければならないのでしょうか?

  • 関数のプロトタイプ宣言

    #include <stdio.h> #define N 3 #define M 4 int sum(int [][M]); (関数のプロトタイプ宣言) int main(){   ・   ・   ・ return(0); } int sum(int x[][M]){    ・    ・ } 以上のプログラムより、関数のプロトタイプ宣言や、関数内の 行列の定義でint sum(int [][M]);や int sum(x[][M]){}となっていますが なぜ、列にMだけを代入することだけでよいのでしょうか? また、教科書に関数のプロトタイプ宣言ではint sum(int [][]);だけでもよいと書かれていたのですが 実際、コンパイルしてみたところ 'int[]' 型のサイズは未知あるいはゼロとエラーがでました。 これは、コンパイラによってできるものとできないものがあるのでしょうか?? よろしくお願いします。

  • C言語 プロトタイプ宣言のスコープ

    現在、C言語の勉強中です。 プロトタイプ宣言は関数内で宣言をすることは可能でしょうか。 その際、宣言が有効なのはその関数内ということになりますか? OS:windows7 VS2010 express で次のプログラムを記述してもコンパイルエラーにはなりませんでした。 もし、プロトタイプ宣言もスコープを持つとしたら、関数plus()の中でminus() を呼び出したところでwarningかエラーをはくと考えましたが、出ませんでした。 どなたか、教えてください。 #include <stdio.h> int main(void){ char* plus(void); //プロトタイプ宣言 char* minus(void); // char *ans; ans = plus(); printf("mainFunc = %s", ans); ans = minus(); printf("mainFunc = %s", ans); } char* plus(){ char *answer; //関数の戻り値はポインタ answer = minus(); //プロトタイプ宣言なしで関数を使用 printf("plusFunc = %s",answer); return "plus success\n"; } char* minus(){ return "minus success\n"; }

  • 関数のプロトタイプ宣言の文法は次のようになります。

    関数のプロトタイプ宣言の文法は、次のようになります。   型 関数名(引数);  関数定義から処理部分を取り除き、ひとつのステートメントとして完結するように、文末に; を付けてたものになります。  基本的に関数を呼び出すための形式を宣言するためのものですから、型、関数名、引数は 関数定義と同じになります。プロトタイプ宣言は、対象となる関数を呼び出す前に行う必要があります。     以上は参考書の説明ですが!「関数定義から”処理部分”を取り除き」とあります。  その中の”処理部分”とは何を指すのでしょうか!?  宜しくお願いします。  

  • C言語 関数プロトタイプ宣言の引数に配列を入れたいのですが

    関数プロトタイプ宣言(自作関数)の引数に、A[4][4]というような配列を入れたいのですが、コンパイル時にエラーでincompatibleといわれてしまいます。 A[0][0]からA[3][3]までを個別に引数に指定してもエラーになります。 良い方法は無いでしょうか?

  • 静的解析を試すから適当に送って・・・

    請け負っているソース修正作業中のファイルで静的解析を試すので適当なものを送ってください、と指示されたのですが、 最低限、解析を通す関数が1つ以上で、コーディング規約に合わせ、コンパイルエラーと警告なしが条件でした。 以下の手順で提出用のファイルを用意しました。 1.1つのソースファイルから適当に1つの関数をピックアップし、   他の関数はすべて消しました。プロトタイプ宣言も消しました。 2.残った関数が必要としないincldeを消しました。 3.コーディング規約に沿って修正しました。include先のヘッダファイルには何も手をつけていません。 4.現段階で定義されているファイルがない変数やメソッドがあったので、適当な位置にダミーを記述しました。 5.ビルドすると当たり前ですがmain関数がない、とのエラーが出たので、何の動作もしないmain関数を書きました。 これでエラー、警告はなくなりましたが、果たしてこれで解析ができるのか心配です。 常識的に間違っている箇所があればご指摘くださいますでしょうか。

  • extern "C"が原因?

    今、自分のソースから既存の(sample.h)をインクルードし、 そのヘッダファイルの変数を用いようと思っているのですが、 「error LNK2001: 外部シンボル "ID_WMP" は未解決です。」というエラーが出ます。 (sample.h) extern "C" const GID ID_WMP 自分のソース(my.h)で、このID_WMPを使用すると、上記のエラーがでます。 困っています。よろしくお願い致します。

  • 自作ヘッダファイルについて (C言語)

    自作ヘッダファイルについて質問なのですが、ヘッダファイルには外部変数や関数のプロトタイプ宣言を記述しますよね?では関数の実装はどこで行ったらいいのでしょうか?回答よろしくお願いします。

  • 定義されているのにエラーになる

    閲覧ありがとうございます。 C言語のプログラムの話です。 ソースファイルaaa.cでstdio.hをincludeしています。 stdio.hには extern FILE _iob[_NIOBRW]; というのが定義されているにも関わらず、 コンパイルすると、 aaa.o:aaa.c:(.data+0x58): undefined reference to '_iob' というエラーが出ます。 aaa.cでは_iobに関する宣言はしていませんが、それを使うこともしていません。 ヘッダファイルでexternで宣言してるからかなと思い、ソースファイルにexternなしの宣言を書き足したら、コンパイルは通りました。 今回は元々既にあるプロジェクトの改修だったのですが、宣言を消したりしていません。 しかし、その部分は元々ヘッダファイルに宣言などしなくてもコンパイルが通ってました。 昔はヘッダファイルでexternで宣言してたらソースファイルではしなくてオッケーみたいな感じだったんですかね? 私自身、あまりよく分かってなくて文章もめちゃくちゃですみません。 不足している情報があればできる範囲でお伝えしますので、ご協力よろしくお願いいたします。

このQ&Aのポイント
  • 鉄骨製作工場名表示のカンバンの記載方法について詳しく教えてください。
  • 鉄骨製作工場のカンバンにはどのような情報を表示すべきですか?
  • 鉄骨製作工場のカンバンにおいて、代表者指名と所在地の表記方法について知りたいです。
回答を見る