K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[193] C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

 初めまして、九龍と申します。  C言語でのプログラム経験は結構長いのですが、ある事が分からなかったので、C言語ポインタ完全制覇に購入させて頂きました。  それで、現在読んでいる真っ最中なのですが、p303ページに記載されている「fは勝手にdoubleに読み替えられているので,当然正しく渡らないことになります.」の意味が分かりません。  上記は、仮引数float fは、double fと読み替えられているため、fのポインタを渡しても、void sub_func 関数では、floatへのポインタで間接参照されるため、正常に参照されないということでよろしいのでしょうか?  一生懸命意味を理解しているつもりですか、拙い理解能力で申し訳ありません。  後、もし宜しければexternとリンケージに関する事も教えて頂ければと思います。  p80の脚注にも出てきているので、ちょっとインターネットで調べてみたのですが(http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide82-1.html)、見た瞬間に定義宣言と参照宣言、関数プロトタイプ宣言がごっちゃになりました。  (なにせ今まで、どこかで定義宣言をしている変数を参照する場合には、externを付ければ良いぐらいにしか思ってなかったんで。)  宜しくお願い致します。
[この投稿を含むスレッドを表示] [この投稿を削除]
[194] Re:C言語ポインタ完全制覇についての質問
投稿者:(ぱ)
2007/02/20 02:13:25

> 初めまして、九龍と申します。 > C言語でのプログラム経験は結構長いのですが、ある事が分からなかったので、 > C言語ポインタ完全制覇に購入させて頂きました。 はじめまして。お買い上げいただきありがとうございます。 > それで、現在読んでいる真っ最中なのですが、p303ページに記載されている >「fは勝手にdoubleに読み替えられているので,当然正しく渡らないことになります.」 > の意味が分かりません。 > 上記は、仮引数float fは、double fと読み替えられているため、fのポインタを >渡しても、void sub_func 関数では、floatへのポインタで間接参照されるため、 >正常に参照されないということでよろしいのでしょうか? そうです…と答えると一言で終わってしまうわけですが、何か疑問があるので 質問されたのだと思います。そこをもう少し明確にしていただけると、何か回答 できるかもしれません。 たとえばfloat 4バイト、double 8バイトの処理系を仮定したとして、fは実は doubleなので 8バイトです。その領域をfloat *で読めるはずはないわけです。 > 後、もし宜しければexternとリンケージに関する事も教えて頂ければと思います。 > p80の脚注にも出てきているので、ちょっとインターネットで調べてみたのですが >(http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide82-1.html)、見た瞬間に >定義宣言と参照宣言、関数プロトタイプ宣言がごっちゃになりました。 そのページにあるように、外部結合とは、 | プログラムが複数のソースファイルから構成される場合,それらすべての | ソースファイルにおいて同一のオブジェクト,或いは関数として参照。 ですよね? それに対し内部結合はそのソースファイルの中だけで有効なリンケージです。 関数や変数を内部結合にするためにはstaticを付けますが、 外部結合の場合、定義では何もつけず、宣言ではexternを付ける…と決まっていれば 説明が楽なのですが、実際には、 ・どこかで定義されている変数を参照する場合、externを付けなくても、たいていの  処理系では何のエラーにもならない(p.317を参照) ・どこかで定義されている関数を使う場合、プロトタイプ宣言を行うが、  これにはexternをつけても付けなくても良い(で、たぶん普通はつけない) ということで、説明がややこしくなっています。 > (なにせ今まで、どこかで定義宣言をしている変数を参照する場合には、 > externを付ければ良いぐらいにしか思ってなかったんで。) この認識で正しいと思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[198] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

 (ぱ)さん、はじめまして。  丁寧なご解答ありがとうございます。 >そうです…と答えると一言で終わってしまうわけですが、何か疑問があるので >質問されたのだと思います。そこをもう少し明確にしていただけると、何か回答 >できるかもしれません。 >たとえばfloat 4バイト、double 8バイトの処理系を仮定したとして、fは実は >doubleなので 8バイトです。その領域をfloat *で読めるはずはないわけです。    するどいですね。実は私が最初に思ったのが、どうせ仮引数でdoubleしか渡せないのなら、void sub_funcの関数宣言でのfloatへのポインタの仮引数宣言は、doubleへのポインタに読み替えられているのではないかという勝手な勘違いです。  それでちょっと心配になったのでご質問させて頂きました。  後、externとリンケージについての解答もありがとうございます。 >・どこかで定義されている関数を使う場合、プロトタイプ宣言を行うが、 > これにはexternをつけても付けなくても良い(で、たぶん普通はつけない)  昔、プロトタイプ宣言にexternをつけていたプログラムがあったので、一時期付けていた記憶があります。  話はちょっと脱線しますが、http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide82-1.htmlにある解説、表はちょっと分かりずらいと思うのですが…。  例えば、別のモジュールで定義宣言されている関数を、他のモジュールの関数ブロック内でextern void f (void)とすると(普通はこんなことしませんが)、その関数ブロック内だけでその関数への参照が可能だと思っていたのですが、それより下の関数定義ブロック内でも参照可能となっていました(VC++ 6.0で確認)。  変数の場合であれば、その関数ブロック内のみ有効な筈ですが…。  うーん、ややっこしい。  ちょっと長くなりそうなので、この辺でやめておきます。  これからもちょくちょく寄らせて頂きますので、宜しくお願い致します。
[この投稿を含むスレッドを表示] [この投稿を削除]
[199] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

>>・どこかで定義されている関数を使う場合、プロトタイプ宣言を行うが、 >> これにはexternをつけても付けなくても良い(で、たぶん普通はつけない) つけてもつけなくても良い、というか単純に省略時解釈なだけですね。 int hoge(void); という関数宣言は extern int hoge(void); と解釈されます。 void piyo(void) {} という関数定義は extern void piyo(void) {} と解釈されます。 extern がついているので外部結合となるわけです。 あと C と C++ では規則が少し変更されていて --a.cpp-- int g; --b.cpp-- int g; とするとエラーになります (One Definition Rule : ISO/IEC 14882:1998 3.2) C の場合 ODR の規定がありません。 そのため、過去のコンパイラ用に書かれたコードとの互換性のために、 「複数個の翻訳単位で同一名称の変数が定義されたら、それを同一の実体とみなす」 処理系がほとんどです。 # そーいうコードが多く残っているので。
[この投稿を含むスレッドを表示] [この投稿を削除]
[200] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

774RRさん、はじめまして。 >>>int hoge(void); という関数宣言は extern int hoge(void); と解釈されます。 >>そのため、過去のコンパイラ用に書かれたコードとの互換性のために、 >>「複数個の翻訳単位で同一名称の変数が定義されたら、それを同一の実体とみなす」 >>処理系がほとんどです。 という事は、他の翻訳単位のファイルスコープ(外部宣言)で同一識別子で変数定義宣言をおこなった場合でも、省略時解釈ではexternになるために省略可能(でも普通は区別する為に付けますが)って解釈で宜しいのでしょうか?
[この投稿を含むスレッドを表示] [この投稿を削除]
[201] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

関数宣言と変数宣言では話が違います。 関数宣言の省略時解釈は extern つまり外部結合ありです。 関数定義においても省略時解釈は extern つまり外部結合ありです。 関数定義と関数宣言とでは書式が違うので誤解を生む余地が無く、問題は発生しません。 大域変数の「定義にならない宣言」の場合は extern が必須です。 extern を書かずに大域変数を宣言し、初期化子が無い場合 ・C の場合:変数の仮定義となります。仮定義は複数個あってかまいません。 ・C++ の場合:変数の定義となります。定義は1つしか許されません。 ・C/C++ とも、その大域変数は外部結合となります。 --a.c-- extern int g; /* 定義にならない宣言 */ int g; /* 仮定義 */ int g=1; /* 定義 */ C の場合、言語規格は 「同一翻訳単位中に同一名称の大域変数の複数個の仮定義がある」ことを認めています。 「複数翻訳単位中に同一名称の大域変数の定義がある」ことは定めておらず、 たいていの処理系では全翻訳単位での定義を1つにまとめてしまいます。 ==b.cpp== extern int g; /* 定義にならない宣言 */ int g; /* 定義 */ int g=1; /* 再定義:エラー */ C++ の場合、仮定義などというものはないので 「同一翻訳単位中に同一名称の大域変数の複数個の定義がある」 「複数翻訳単位中に同一名称の大域変数の複数個の定義がある」 の両方が言語規格上、認められずエラー発生となります。 http://www2s.biglobe.ne.jp/~hig/q_a/Programing_QA02.html
[この投稿を含むスレッドを表示] [この投稿を削除]
[203] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

774RRさん、度々申し訳ありません。 すばやいレスありがとうございます。 つまり、 --a.c-- int a = 1; // 定義 --b.c-- int a; // 仮定義 上記の場合だと、b.cのint a;が仮定義なので、a.cで定義されているint a = 1;のオブジェクトとまとめられたと言うことで、b.cのint a;がextern int a;と解釈されている訳ではないという解釈で宜しいでしょうか? (774RRさんがお書きになったリンク先の13番目の項目に該当するので、結局それは処理系依存になる為、VC++ 6.0ではまとめられて解釈されたというような解釈で宜しいでしょうか?) 後、くだらない事をお聞きしますが、 -- a.c -- #include <stdio.h> extern void f (void); // a.c の関数 f と結び付く(通常externは付けないけど) int main (void) { f (); return 0; } static void f (void) { printf ("a.c の関数 f\n"); } -- b.c -- #include <stdio.h> extern void f (void) { printf ("b.c の関数 f\n"); } の場合、main関数のf関数の呼び出しは、a.cにある関数fとなりますが、この場合のextern void f (void)の関数プロトタイプ宣言のリンケージ属性はどうなるのでしょうか? くだらない質問ですが、宜しくお願い致します。
[この投稿を含むスレッドを表示] [この投稿を削除]
[204] Re:C言語ポインタ完全制覇についての質問
投稿者:(ぱ)
2007/02/20 02:13:25

> どうせ仮引数でdoubleしか渡せないのなら、void sub_funcの関数宣言での >floatへのポインタの仮引数宣言は、doubleへのポインタに読み替えられて >いるのではないかという勝手な勘違いです。 それをやっちゃうと、swap(float *a, float *b)のような関数で困りますし。 > 例えば、別のモジュールで定義宣言されている関数を、他のモジュールの >関数ブロック内でextern void f (void)とすると(普通はこんなことしませんが)、 >その関数ブロック内だけでその関数への参照が可能だと思っていたのですが、 >それより下の関数定義ブロック内でも参照可能となっていました(VC++ 6.0で確認)。 もともと、プロトタイプ宣言なんて書かなくても(警告は出ても)動きますから、 結合はされるとしても、プロトタイプ宣言の有効範囲は微妙な問題のように 思います。 以下のソースをbcc32でコンパイルしたところ、 void hoge1(void) { extern void piyo(int a); piyo(1); } void hoge2(void) { piyo(2); } こんなエラーが出ました。 エラー E2356 proto2.c 10: 'piyo' の再宣言で型が一致していない(関数 hoge2 ) エラー E2344 proto2.c 3: 一つ前の 'piyo' の定義位置(関数 hoge2 ) hoge2のブロックの先頭に「extern void piyo(int a);」を入れると ちゃんと通るので、少なくともbcc32においては、hoge1()内部の宣言がそのまま hoge2()内部で有効になっているというわけではないようです。 この件について規格書になにか書いてないかとぱらぱらめくったのですが 見つけられませんでした。 ご存知の方がいらっしゃいましたら情報よろしくお願いいたします(_o_)
[この投稿を含むスレッドを表示] [この投稿を削除]
[205] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

>それをやっちゃうと、swap(float *a, float *b)のような関数で困りますし。 なるほど。仰られる通りです。 >もともと、プロトタイプ宣言なんて書かなくても(警告は出ても)動きますから、 >結合はされるとしても、プロトタイプ宣言の有効範囲は微妙な問題のように >思います。 > >以下のソースをbcc32でコンパイルしたところ、 > >void hoge1(void) >{ > extern void piyo(int a); > > piyo(1); >} > >void hoge2(void) >{ > piyo(2); >} > >こんなエラーが出ました。 >エラー E2356 proto2.c 10: 'piyo' の再宣言で型が一致していない(関数 hoge2 ) >エラー E2344 proto2.c 3: 一つ前の 'piyo' の定義位置(関数 hoge2 ) > >hoge2のブロックの先頭に「extern void piyo(int a);」を入れると >ちゃんと通るので、少なくともbcc32においては、hoge1()内部の宣言がそのまま >hoge2()内部で有効になっているというわけではないようです。 > >この件について規格書になにか書いてないかとぱらぱらめくったのですが >見つけられませんでした。 わざわざ規格書まで調べて頂き有り難うございます。 と、ゆうことは処理系依存って事なんでしょうね…。
[この投稿を含むスレッドを表示] [この投稿を削除]
[206] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

リンク先の12番の解説を文字通りに解釈してください。 仮定義(初期化子なし定義)だけがあって、初期化子あり定義が無い場合、 翻訳単位のEOFに達した時点で仮定義は定義となります。 --hoge.c-- int x; // 仮定義 int x; // 仮定義:何回仮定義が現れても(既存の宣言に反しない限り)問題ない int x; // 仮定義 --EOF of hoge.c-- この時点で int x=0; と定義されたことになる。 >上記の場合だと、b.cのint a;が仮定義なので、 この文章はある意味YES、ある意味NO。確かに int a; は仮定義ですが、既に述べたとおり 翻訳単位 (b.c) の EOF に達した時点で、仮定義は「仮ではない『定義』」になります。 よって提示の例では a.c b.c ともに変数 a が定義されています。 そこではじめてリンク先13番目の解説が効いてきます。 >a.cで定義されているint a = 1;のオブジェクトとまとめられたと言うことで 「仮定義だからまとめられた」のではありません。 「C では、定義が複数ある場合の挙動が定められていない」(未定義動作) →「エラーにするのも、定義を1つにまとめるのも処理系の実装次第」 →→「多くの C 処理系では定義を1つにまとめちゃう」 となっただけです。 >b.cのint a;がextern int a;と解釈されている訳ではないという解釈で宜しいでしょうか? コンパイラは int a; を勝手に extern int a; と解釈しません。 そのへん関数宣言と変数宣言で文法が違う場所です。
[この投稿を含むスレッドを表示] [この投稿を削除]
[207] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

774RRさん、度々申し訳ありません。 >リンク先の12番の解説を文字通りに解釈してください。 >仮定義(初期化子なし定義)だけがあって、初期化子あり定義が無い場合、 >翻訳単位のEOFに達した時点で仮定義は定義となります。 >--hoge.c-- >int x; // 仮定義 >int x; // 仮定義:何回仮定義が現れても(既存の宣言に反しない限り)問題ない >int x; // 仮定義 >--EOF of hoge.c-- >この時点で int x=0; と定義されたことになる。 > >>上記の場合だと、b.cのint a;が仮定義なので、 >この文章はある意味YES、ある意味NO。確かに int a; は仮定義ですが、既に述べたとおり >翻訳単位 (b.c) の EOF に達した時点で、仮定義は「仮ではない『定義』」になります。 >よって提示の例では a.c b.c ともに変数 a が定義されています。 >そこではじめてリンク先13番目の解説が効いてきます。 > >>a.cで定義されているint a = 1;のオブジェクトとまとめられたと言うことで >「仮定義だからまとめられた」のではありません。 >「C では、定義が複数ある場合の挙動が定められていない」(未定義動作) >→「エラーにするのも、定義を1つにまとめるのも処理系の実装次第」 >→→「多くの C 処理系では定義を1つにまとめちゃう」 >となっただけです。 > >>b.cのint a;がextern int a;と解釈されている訳ではないという解釈で宜しいでしょうか? >コンパイラは int a; を勝手に extern int a; と解釈しません。 >そのへん関数宣言と変数宣言で文法が違う場所です。 なるほど。理解できました。 ご丁寧な解説、ありがとうございます。
[この投稿を含むスレッドを表示] [この投稿を削除]
[208] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

C 規格書はウチに帰らないと無いのでアレげですが C++ 規格書であれば 「JIS X3014:1998-3.3.2 局所的な有効範囲」で、 ブロック内に宣言された名前はそのブロックに局所的である。 と書かれています。実際以下のコードはコンパイルエラーです。 ---hoge.cpp--- int func1(void) { extern int piyo(void); return piyo(); } int func2(void) { return piyo(); } ---EOF of hoge.cpp--- んで、上記を hoge.c とした場合の挙動ですが bash-3.0$ hppa2.0w-hp-hpux11.00-gcc-3.3.4 -Wall -c hoge.c hoge.c: In function `func2': hoge.c:7: warning: implicit declaration of function `piyo' Microsoft Visual C++ 6.0SP6 だと cl -W4 -c hoge.c hoge.c(2) : warning C4210: 非標準の拡張機能が使用されています : 関数にはファイル スコープが与えられています。 hoge.c(7) : warning C4217: 非標準の拡張機能が使用されています : 以前のブロックでの関数宣言です。 となりました。 やはり言語規格がスコープ詳細等を定めていないようです。 # IE6 でも Acrobat Reader を uninstall してから JIS 閲覧するとゲフガフ # って検索が効かない文書なので、むりくり保存してもあまり役に立たない鴨。
[この投稿を含むスレッドを表示] [この投稿を削除]
[209] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

おっと自己レス。 cl -W4 -Za -c hoge.c だと hoge.c(7) : warning C4013: 関数 'piyo' は定義されていません。int 型の値を返す外部関数と見なします。 となるのでやはりブロックスコープなのが本来みたいですね。 ブロックスコープを超越して大域に関数宣言が有効になるのは(互換性のための)拡張機能、と。 # 規格書を要確認だなこりゃ。
[この投稿を含むスレッドを表示] [この投稿を削除]
[210] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

申し訳ございません。コンパイラの警告レベルを4に上げるの忘れてました…(面目ないです)。 ちなみに、警告レベル3では何も出ませんでした。 >cl -W4 -Za -c hoge.c だと >hoge.c(7) : warning C4013: 関数 'piyo' は定義されていません。int 型の値を返す外部関数と見なします。 >となるのでやはりブロックスコープなのが本来みたいですね。 Microsoft言語拡張機能の無効スイッチですね(全然気にしてませんでした。これからは切るようにします…)。 確かに、これを見るとブロックスコープなのが本来の仕様みたいですね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[211] Re:C言語ポインタ完全制覇についての質問
投稿者:(ぱ)
2007/02/20 02:13:25

>C++ 規格書であれば 「JIS X3014:1998-3.3.2 局所的な有効範囲」で、 >ブロック内に宣言された名前はそのブロックに局所的である。 >と書かれています。実際以下のコードはコンパイルエラーです。 C でも、6.1.2.1 を見る限り、ブロック内で宣言された識別子のスコープは ブロック内ですから、プロトタイプ宣言もブロック内だけで有効と考えるのが 自然なように思います。 ただ、ふたつのコンパイラで、単純にそうとは言えない動きをしているので、 どこか別に規定があるのかと、昨晩は規格書をひっくり返していたのでした。 >んで、上記を hoge.c とした場合の挙動ですが >bash-3.0$ hppa2.0w-hp-hpux11.00-gcc-3.3.4 -Wall -c hoge.c >hoge.c: In function `func2': >hoge.c:7: warning: implicit declaration of function `piyo' これはプロトタイプ宣言がない場合の通常の挙動ですよね。 だから、gccでは、ちゃんとブロックでスコープが終了していて、 C++ではだめなのは、C++ではそもそもプロトタイプ宣言がないことを許さないからで。 bcc32ですが、 extern void piyo(int a); と書いていたのを、 extern int piyo(int a); にしたら通りました。 推測するに、 a)hoge1()の中のpiyoの宣言はhoge1()の中で完結していて、 b)hoge2()の中のpiyoの呼び出しで、宣言がないので暗黙にintを返す関数として  宣言されて、 c)その宣言の段階で、既存の宣言との整合性がチェックされ、なぜかこのときは  hoge1()の中での宣言とのチェックも行っていて、そのためにエラーになった。 ということでしょうかね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[212] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

>ということでしょうかね。 と思います。C++ と違い C の場合、K&R1 の頃の(いわゆる non-ansi C) との後方互換性を 保つため、規格書に書かれていない(もしくは規格書が禁じている)後方互換のための機能が いくつも有効になっている処理系がほとんどのようです。 VC++ や BCC なんかはその典型ですね。 # 関数宣言のスコープ拡大なんかはその一例。 gcc の場合、後方互換な機能が使われると警告を出すオプションがあったりしますが... あまり関係ありませんが、コンパイラの警告メッセージの翻訳チームは規格書を理解して 細心の注意を払って訳しているのか、かなり疑問。 宣言と定義は用語の意味が違うのですが、どう見ても混同していると思われます。 >エラー E2356 proto2.c 10: 'piyo' の再宣言で型が一致していない(関数 hoge2 ) >エラー E2344 proto2.c 3: 一つ前の 'piyo' の定義位置(関数 hoge2 ) 前者は正しく『宣言』ですが、後者は『定義』ではなく宣言であるはずです。 >hoge.c(7) : warning C4013: 関数 'piyo' は定義されていません。int 型の値を返す外部関数と見なします。 これもヘン。ここは『宣言』でなければならないはずです。 >hoge.c:7: warning: implicit declaration of function `piyo' gcc の英語は正しく「宣言」と言っています。 gcc-3.3.4 の gcc/po/ja.po を見たところほぼ正しく翻訳しているようですが、 一部やはり誤訳を発見。あぁ、フィードバックしないといけないかも?
[この投稿を含むスレッドを表示] [この投稿を削除]
[213] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

>bcc32ですが、 > > extern void piyo(int a); > >と書いていたのを、 > > extern int piyo(int a); 一応、VC++ 6.0(SP6)でテストしてみました。 --a.c-- void hoge1 (void); void hoge1(void) { extern int piyo(int a); piyo(1); } void hoge2(void) { piyo(2); } --b.c-- int piyo (int a) { return a; } c:\cppsrc\a\a.c(11) : warning C4013: 関数 'piyo' は定義されていません。int 型の値を返す外部関数と見なします。 となりました。 しかし、 >a)hoge1()の中のpiyoの宣言はhoge1()の中で完結していて、 なのに、既存の宣言(hoge1の関数ブロック内の宣言)との整合性がチェックされているとは…。 >あまり関係ありませんが、コンパイラの警告メッセージの翻訳チームは規格書を理解して >細心の注意を払って訳しているのか、かなり疑問。 >宣言と定義は用語の意味が違うのですが、どう見ても混同していると思われます。 同感です。 私もコンパイラの警告メッセージで理解に苦しむ時があります。
[この投稿を含むスレッドを表示] [この投稿を削除]
[214] Re:C言語ポインタ完全制覇についての質問
投稿者:れぷ
2007/02/20 02:13:25

横レスすいません。 >c)その宣言の段階で、既存の宣言との整合性がチェックされ、なぜかこのときは > hoge1()の中での宣言とのチェックも行っていて、そのためにエラーになった。 ローカルでexternするにしてもグローバルでexternするにしても、 piyo()は外部に定義あるわけですよね。 例えば、externする側をa.c、ローカルextern用のpiyo()を定義したものをb.c、 グローバルextern用のpiyo()を定義したものをc.cしたとして、 どちらのpiyo()をローカルへリンクして、もう一方をグローバルでリンクすれば良いのか、 コンパイラこれを判断するにはどうすることが良いのでしょうか? b.c、c.cの関数定義はいずれにせよグローバルにおかれるでしょうし、 コンパイラもそれを想定していると考えるなら衝突することになるのかな、なんて思いました。 あー、なんかまた外したこと言ってそう(;_;)
[この投稿を含むスレッドを表示] [この投稿を削除]
[215] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

れぷさん、はじめまして。 >例えば、externする側をa.c、ローカルextern用のpiyo()を定義したものをb.c、 「ローカルextern用のpiyo()を定義したもの」とありますが、どのような意味なのか理解しかねております。 具体的にどういうソースかをお書き頂けると嬉しいのですが。
[この投稿を含むスレッドを表示] [この投稿を削除]
[216] Re:C言語ポインタ完全制覇についての質問
投稿者:れぷ
2007/02/20 02:13:25

九龍さん、はじめまして。  3つに別けたのはa.cのコードが以下のような状況を想定しているように思えたからです。 ---a.c--- void hoge1(void) { extern void piyo(int a); // b.c内を想定 piyo(1); } void hoge2(void) { piyo(2); // c.cを想定 }  なので、↓こういう状況を考えたわけです。 ---b.c--- // hoge1()ではAさんがくれたこっちを使おうと思った void piyo(int a) { return; } ---c.c--- // hoge2()ではBさんがくれたこっちを使おうと思った int piyo(int a) { return a; }  この状態でb.c内にあるpiyo()をhoge1()ローカルだけに対して定義できるかというとできないですよね。 従って、hoge1()でローカルexternしたpiyo()はどこにあるのかというと、 コンパイラは「外部にある関数はグローバルに存在すると想定する」としかないのかな、と思います。 そうなると、   「hoge1()でローカルexternされてるpiyo()はグローバルにあるはず」   「hoge2()のpiyo()はプロトタイプ宣言ないけどこれも多分グローバルにあるはず」 になるので、a.cのコンパイル時に正しいpiyo()をリンクするための情報を作るには 「正しいpiyo()はどれですか?」と整合エラーを吐くしかないような気がしました。  名前空間があれば解決できるのでしょうが、Cは空間分けがザックリすぎて(^-^;) それができないですよね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[217] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

C の場合は名前空間わけがざっくりすぎるし、オーバーロードは無いので、 結局同一名称の関数は1つしか存在し得ないわけです。では >int func1(void) { > extern int piyo(void); > return piyo(); >} の意図はというと、 「この extern を {} 外に出してしまうと同一翻訳単位中の他の関数から piyo() が正しく  呼び出せてしまって警告にならない」 ことを防止することにあります。 piyo() は func1() 専用の作業関数であることを明示したい、と。 だから func2() からは piyo() を呼び出せない、ないしは、 呼び出そうとすると警告になってほしい、わけですね。 # C++ ではきっちりエラーになってくれる。 ではない?
[この投稿を含むスレッドを表示] [この投稿を削除]
[218] Re:C言語ポインタ完全制覇についての質問
投稿者:本多
2007/02/20 02:13:25

宣言した関数が宣言のあるブロック内でのみ有効と明示したいんでしょうね。 でも、C言語を使っていると型はコンパイル後に情報が残らないので、 同じ名前が二つ残ったら、リンクエラーになるんですね。 宣言を関数ブロックに入れるというのが、かなり異常な使い方だと思いますが。 実際、以下の様になってると宣言は何の効果も発揮しません。 ----test1.c---- #include <stdio.h> static int hoge(void) { printf("static int hoge()\n"); return 0; } int main(void) { extern int hoge(void); hoge(); return 0; } ----test2.c---- #include <stdio.h> int hoge(void) { printf("extern int hoge()\n"); return 0; } ---- % gcc -O2 -Wall test1.c test2.c % a.out static int hoge() まぁ、コンパイラがリンク処理を行う段階でexternなんていう情報は すっかり消えうせて関数名だけ残ってしまう。 しかも、名前の一致する呼び出し元と実体をリンク処理しちゃう。 だから処理内容を考えると当たり前の結果なんでしょうけど。 宣言で自分の結合先を選べるという意図があったとして、結果がこうなったら、 私の例はstaticを使ってるのでちょっと事情は異なりますが ちょっと残念に思うかもしれませんね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[220] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

> 例えば、externする側をa.c、ローカルextern用のpiyo()を定義したものをb.c、  仰っている意味が分かりました。  ローカルextern用のpiyo()は、a.cのローカルextern用の関数定義って事だったんですね。 > 例えば、externする側をa.c、ローカルextern用のpiyo()を定義したものをb.c、 > グローバルextern用のpiyo()を定義したものをc.cしたとして、 > どちらのpiyo()をローカルへリンクして、もう一方をグローバルでリンクすれば良いのか、 > コンパイラこれを判断するにはどうすることが良いのでしょうか? > b.c、c.cの関数定義はいずれにせよグローバルにおかれるでしょうし、 > コンパイラもそれを想定していると考えるなら衝突することになるのかな、なんて思いました。 > 名前空間があれば解決できるのでしょうが、Cは空間分けがザックリすぎて(^-^;) > それができないですよね。  774RRさんも、 > C の場合は名前空間わけがざっくりすぎるし、オーバーロードは無いので、 > 結局同一名称の関数は1つしか存在し得ないわけです。では  と仰っているので、C++の名前空間的な機能が無い限り衝突はされられないので、それはできないという結論になると思います(少なくても私の知っている限りでは)。  ローカルのextern宣言の意味については774RRさんの仰っている通りです。  一応念の為に書いておきますが、b.cのpiyoをa.cのhoge1専用の作業関数としたい場合にはstaticを付けて、翻訳単位を分けるという方法しかないと思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[221] Re:C言語ポインタ完全制覇についての質問
投稿者:れぷ
2007/02/20 02:13:25

> と仰っているので、C++の名前空間的な機能が無い限り衝突はされられないので、それはできないとい >う結論になると思います(少なくても私の知っている限りでは)。 そうなりますね。 実は私が反応したのはお二方の文、   >>a)hoge1()の中のpiyoの宣言はhoge1()の中で完結していて、   >なのに、既存の宣言(hoge1の関数ブロック内の宣言)との整合性がチェックされているとは…。 だったりします。 なので「外部関数はグローバルにあると想定するしかない」→「だから整合チェックがかかるのでは?」と思ったわけです。 ちなみにstaticを使ってしまうと、最初のソースの記述では hoge1()もhoge2()もstaticのほうを呼び出してしまうので、 元のソースとは構成を変える必要が出てしまいますね(^-^;)
[この投稿を含むスレッドを表示] [この投稿を削除]
[222] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

れぷさんへ。 > a)hoge1()の中のpiyoの宣言はhoge1()の中で完結していて、 > b)hoge2()の中のpiyoの呼び出しで、宣言がないので暗黙にintを返す関数として > 宣言されて、 > c)その宣言の段階で、既存の宣言との整合性がチェックされ、なぜかこのときは > hoge1()の中での宣言とのチェックも行っていて、そのためにエラーになった。 なので、 「a)hoge1()の中のpiyoの宣言はhoge1()の中で完結していて、」なのですが、 最終的には、 「c)その宣言の段階で、既存の宣言との整合性がチェックされ、なぜかこのときは  hoge1()の中での宣言とのチェックも行っていて、そのためにエラーになった。 」 となるので、前者の文章は「完結していて」が「完結していない」という結論になります。 (チェックされていればhoge1で完結している事にはなりませんので、(ぱ)さんは完結していないと仰りたかったんだと私は解釈しております。間違ってたらごめんなさい。) という訳で(私の解釈が正しければ)、bcc32では774RRさんが仰っている > と思います。C++ と違い C の場合、K&R1 の頃の(いわゆる non-ansi C) との後方互換性を > 保つため、規格書に書かれていない(もしくは規格書が禁じている)後方互換のための機能が > いくつも有効になっている処理系がほとんどのようです。 となります。 という訳でして、hoge1()のextern宣言時では「外部関数はグローバルにあると想定するしかない」ですよね。 で、宣言が完結していていない(コンパイラが余計(?)なことをしてくれるため)ため、「外部関数はグローバルにあると想定するしかない」がhoge2にも摘要されるので、れぷさんの仰る通り、 > なので「外部関数はグローバルにあると想定するしかない」→「だから整合チェックがかかるのでは?」と思ったわけです。 となります。 一応念の為に書いておきます。
[この投稿を含むスレッドを表示] [この投稿を削除]
[223] Re:C言語ポインタ完全制覇についての質問
投稿者:九龍
2007/02/20 02:13:25

自己レスです。 >>a)hoge1()の中のpiyoの宣言はhoge1()の中で完結していて、 >なのに、既存の宣言(hoge1の関数ブロック内の宣言)との整合性がチェックされているとは…。 は、「コンパイラさん、宣言はブロックスコープを越えないで…」というような、私の嘆きの意味合いです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[225] Re:C言語ポインタ完全制覇についての質問
投稿者:れぷ
2007/02/20 02:13:25

>まぁ、コンパイラがリンク処理を行う段階でexternなんていう情報は >すっかり消えうせて関数名だけ残ってしまう。 >しかも、名前の一致する呼び出し元と実体をリンク処理しちゃう。 ここ、私の解釈が間違ってましたね・・・ 本多さんの意図はexternで「外部にあるよ!」と宣言してるにも関わらず、 同一ファイル内に同じ名前があると「外部」を見に行かなくなるってことですね。 # ブロックスコープの「外にある」という風に解釈するのが自然!?
[この投稿を含むスレッドを表示] [この投稿を削除]
[226] Re:C言語ポインタ完全制覇についての質問
投稿者:れぷ
2007/02/20 02:13:25

>は、「コンパイラさん、宣言はブロックスコープを越えないで…」というような、私の嘆きの意味合いです。 なるほど、そうでしたか。 私は「ブロックスコープを超えるのはなんで?」と読めたのでその理由を書き足したのです(^-^;) # とりあえず解決!?
[この投稿を含むスレッドを表示] [この投稿を削除]
[228] Re:C言語ポインタ完全制覇についての質問
投稿者:774RR
2007/02/20 02:13:25

とりあえず以下 C++ の話に限定 (ISO/IEC 14882:1998) 。 # C 規格書はウチに帰r) >externで「外部にあるよ!」と宣言してるにも関わらず、 「プログラマの意図」はそうなのかもしれませんが、言語規格書の主張は違います。 3.5-6 で、こういう宣言を行うと hoge() は内部結合のままだと書かれています。
[この投稿を含むスレッドを表示] [この投稿を削除]
[231] Re:C言語ポインタ完全制覇についての質問
投稿者:れぷ
2007/02/20 02:13:25

>>externで「外部にあるよ!」と宣言してるにも関わらず、 >「プログラマの意図」はそうなのかもしれませんが、言語規格書の主張は違います。 >3.5-6 で、こういう宣言を行うと hoge() は内部結合のままだと書かれています。 ふむふむ。C++だとそう記述があるのですね。 ありがとうございます。
[この投稿を含むスレッドを表示] [この投稿を削除]