サービス情報システム(C言語には関数が存在しないという迷言)
早々に 「C言語には関数の定義はない」 「getcharは関数ではない」 という発言が飛び出してきました. 一体何を言っているのかわからない. もうこの講義についていける気がしません.
7.21.7.6 The getchar function
と思いっきりC11(N1548)に書いてるんですよね.
「HTTPのプロトコルは何を送っても良い」 ?????
授業後に「C言語には関数の定義はない」という言葉の真偽を聞くために,
C言語規格にgetchar
関数が定義されていることを示したら,
「C言語に関数はない」と繰り返し述べて,
私の言うことを間違っていると言ってきました.
「私はISOとJISの規格を参照してgetcharが関数であると述べているのですが, そちらの根拠は何ですか?」 と聞いたら 「K&R」 という返事が帰ってきました.
私がmanにもgetcharはPOSIX.1-2001, POSIX.1-2008, C89, C99.と書いてあるのでC言語の一部だと根拠を示したら, 「manの2と3の違いわかる? わからないとダメだよ」 と関係のないことを返してきました. 確かに私はmanの番号の意味を暗記していませんが, それに何の意味があるのでしょう? manページの内部を見ればどのセクションを見ているのかわかるでしょう. しかもgetcharは3番なのでなおさら標準Cライブラリ関数であることを示しています.
その後も
「getcharはマクロだ」
「規格は関数になっていても実装は関数ではない」ということを言っていましたが,
実際glibcのstdio.h
はextern int getchar (void);
と宣言しています.
と思ったのですが,
なお,getchar はマクロとして実装してもよいことになっています.
C言語関数辞典によると, getcharはマクロでも良いらしいですね. 出典は不明で, 少なくともC11では関数としか書かれていませんでしたが, 古いC言語規格ではマクロバージョンが許されていたのでしょうか?
実際にマクロバージョンを提供している実装もあるそうです. glibcにはマクロ実装は存在していないようでしたが.
getc() は fgetc() と同様だが、 stream を複数回評価するマクロとして実装されているかもしれない。
getchar() は getc(stdin) と同じである。
Linux Programmer's Manual FGETC(3)
よく見ると, Linux Programmer's Manualにも確かにそう書かれています.
しかし, やはり基本は関数でしょう. 規格にはfunctionとしか書かれてなく, 例外などの記述もありませんでしたから. IBMもマルチスレッドサポートを有効にすると関数版のみになると書いてあります. IBM Knowledge Center - getc()、getchar() - 文字の読み取り
また, C11の規格でも, C99の規格にもgetcharがマクロでも許されると書いてなく, それ以上古い規格はweb上で見ることが出来ませんでした. なので, いつのC言語なら許されるのか, そもそも本当に許されていたのか, 規格違反の実装でも動いていただけではないかなどは調べることが出来ませんでした.
C99ですが、7.1.4に
— 株式会社クローバーフィールド (@cloverfield_inc) 2018年1月9日
Any function declared in a header may be additionally implemented as a function-like macro defined in the header,
とありますので、どのライブラリ関数もマクロOKです。ただし、通常の関数も同時に定義されなければなりません。
教えて貰いました.
マクロでの提供を選択して良いということはなく, 関数を提供した上で, マクロで追加的に定義できるそうですね. C11(N1256)でも同様の文面を179ページに確認しました.
「getcharは関数ではない」というのは正しくなく, 「getcharと書いた時関数として呼び出されるとは限らない」が正解のようです.
しかし, そうなると, C言語関数辞典とLinux Programmer's Manualの記述はミスリードを誘いませんか? C言語規格には全てのヘッダーの関数はマクロにより追加実装されても良いと書かれています. しかし, Linux Programmer's Manualなどは一部の関数のみマクロとして実装されているかもしれないと書いています. そう書かれていると他の関数はマクロじゃないことが保証されているんだなと思うのが自然ではないでしょうか. と思ったのですが, Linux Programmer's Manualには以下のように書かれています.
複数回評価するマクロとして実装されているかもしれない
複数回が重要ですね, 私はマクロを読んでいました.
C11規格にも以下のように書いてあります.
The getc function is equivalent to fgetc, except that if it is implemented as a macro, it may evaluate stream more than once, so the argument should never be an expression with side effects.
getc関数はfgetcと等価ですが、マクロとして実装されている場合は、ストリームを複数回評価する可能性があるので、引数は副作用のある式であってはいけません。
なるほど複数回評価する可能性があるという点で特別なのですね.
C言語関数辞典は間違えてませんか?
まあ, getcharが必ず関数かどうかは本筋ではありません. 本筋は「C言語に関数は存在しない」という言葉です.
どうしてもC言語の規格にライブラリが含まれていることを納得してはくれませんでした.
何度も「C言語は関数が自由に定義できるから関数が含まれていない」と言っていました. 関数が自由に定義できるから関数が含まれていないという論理の繋がりがわからないと何度も質問しましたが, 論理の繋がりは説明されないままでした.
最後に宿題の提出がありました. 私は前の授業のインパクトによって完全に宿題の存在を忘れていました. 内容は確かクラウドサービスの比較だった気がするのですが, 日記にも書いてないし, TODOリストにも書いていません. これは素直に私の落ち度ですね. なんで忘れっぽいのにメモをしないのか… メモをすること自体を忘れてしまうんでしょうね. この講義にかなりのリソースを費やしたので, これを落とすのは嫌ですね…