今回のトピックは試験問題が遡上にあがっています。
試験というからには前提となる「ルール」があるはずで
日本国の教員資格の試験であれば、それは JIS 規格であるべきでしょう。
gcc とか (以下略) の個別の実装の話を出すのは
(カルマを減らす or ちゃちゃいれ or 他人をおちょくる or so on が目的でなければ)
そろそろ潮時かな~と愚考する次第です。
# もっともこの話題の発端は Oliver 氏の伝えるところの
# 教授氏のmath-out [tuxedo.org]な話から始まっているので
# 結局はこの教授氏を説き伏せるのにどちら (規格 or 実装) が
# 有効かという話に帰結したりするのかも。
みんなで void main (スコア:0)
教科書にそう書いてあるから。
もう、どうにでもなれって、感じですね。
情報処理学会のどこかの部会かなんかが出した、
情報教育の教科書でも、void main ってなってますよ。
動きゃいいんじゃないの?
もう、知らんって感じ。
Re:みんなで void main (スコア:2, 興味深い)
メソッドは副作用があり、戻り値がない。エラーはExceptionなどの別の方法で通知。
ファクション(関数)は副作用がなく、戻り値がある。戻り値の算出に引数以外に依存すべきではない。
というのが「正しい」姿だからだそうだ。で、mainはメソッドなので、voidでなければいけないそうだ (うちのオブジェクト指向論教授談)。
exit(1)の1ってmain()の戻り値やん、と反論したら、いやー
returnじゃないから、それはthrowと同等だ。とか云々で現実と理想のギャップについて教授と喧嘩してしまった。関数型言語だったら、ここいらは美しいんだけど、imperativeだとね。
Javaの静的タイピング らぶ な教授なんだけど、java.lang.Objectにcastしまくりな現状とRubyみたいな完全動的タイピングについても意見を求めたら.... ってそれは別の話。
Re:みんなで void main (スコア:2)
Re:みんなで void main (スコア:2)
自己フォロー。
教授氏の言わんとするところは、main() が関数であるためには、
のように「return の値は引数だけに依存すべき」だという事ですね?# じゃあ isprint(3) は locale の状態に依存するから
# void じゃないといけないって事?
envp (スコア:0)
Re:envp (スコア:2)
差し支えなければ extern char **environ か getenv(3) を使ったほうがいいでしょう。
Re:envp (スコア:0)
つーか、C言語に「UNIXの方言」っていう表現もなー。
Re:envp (スコア:2)
(「引数だけ」に依存した return の例示なら argc で十分でしょう?) まあ気持ちは分からなくもないんですが これだけ C/C++ が普及 (特に Windows) するとねぇ...。
# Win な若人に「この bzero() って何ですか?」って
# 聞かれたときには「時代は変わった」と思いましたです。
# まあ書いた人にも「今時なら memset() 使えよ」とか
# 思いましたけど。
Re:みんなで void main (スコア:1)
UNIX 系の C の場合,そもそも main() って,なんとかcrtかんとか.o というスタートアップルーチン(?)からコールしている関数に過ぎないのだけれど.というわけで,引数と戻り値については,単になんとかcrtかんとか.o との摺合わせ,という話になるのではないか,と思います.
あと,ライブラリ関数 exit(3) は (linux では) システムコール _exit(2) を呼び出すようです. このシステムコールは,二度と呼び出し元の関数へは制御は戻らないので,「戻り値」というのはまた別だと思います.
規格で決まってるの (スコア:0)
規格は規格,実装は実装 (スコア:1)
サブジェクトの通り :-)
ま,この試験の場合は規格の方に従うべきで,特定の実装に依存するのは好ましくないとは思いますが. ま,UNIX 系 OS ではそういう仕組みになってることが多いので,void main(void) でも矛盾しない実行ファイルが生成できる,というだけの話.
実装なら、現実の実装 (スコア:0)
あくまでも。
そもそも、最初のC言語にvoidはないし。
Re:実装なら、現実の実装 (スコア:2)
更に言えば、DOS/Windows だって int main ですね。 但し「void でも構わない」事が公式に認められているだけで。
void でも構わないとベンダが言明している UNIX のコンパイラは寡聞にして聞いたことがありません (探せば見つかるのかも知れませんが)。
# ちなみに C# では main の戻り値は int でも void でも
# 構わないことになっていたと思います。
# この辺は Java の void な main の向うを張ったのか
# Microsoft の C 方言の名残なのかは意図不明。
Re:実装なら、現実の実装 (スコア:1)
----------
#include <unistd.h>
void Main ( void );
void _start (int argc, char *argv[])
{
write ( 1, "_start\n", 7 );
Main();
_exit ( 0 );
}
void Main ( void )
{
write ( 1, "hello,world\n", 12 );
}
----------
(1)Linux において,このプログラムを
$ gcc -Wall hello.c -S -o hello1.s
$ gcc hello1.s -c
$ ld hello1.o -Bstatic -lc -o hello
と,コンパイルして,実行してみましょう.
(Linux でなくても,gcc を使っている処理系なら動作するとは思いますが,未確認.)
(2)あと,
$ gcc -DMain=main -Wall hello.c -S -o hello2.s
$ gcc hello2.s
$ ld hello2.o -Bstatic -lc -o hello
のコンパイルでは,どのようなワーニングが表示されるでしょうか.
また,このプログラムを実行してみましょう.
(3) (1) で生成される hello1.s と (2) で生成される hello2.s を比較してみましょう.
例えば
$ diff -u hello1.s hello2.s
こんな感じ.
ま,普通にプログラミング・コンパイルしてる分には int main ( int, char ** ) が正しいし,こんなことやっても何のご利益もないのですが.
単にこれが _start から実行されるスタートアップルーチンとの「決まりごと」であって,カーネルインターフェースとは無関係である,というのはわかるとは思います.
そんなこと聞いてないんだけど (スコア:0)
char main[] = { 機械語... };
だって、多くのマシン/OSで動くでしょ。
DOSでも動くし。
まさにこのコード(Re:そんなこと聞いてないんだけど (スコア:2)
...というだけではナンなので。 :-)
今回のトピックは試験問題が遡上にあがっています。 試験というからには前提となる「ルール」があるはずで 日本国の教員資格の試験であれば、それは JIS 規格であるべきでしょう。 gcc とか (以下略) の個別の実装の話を出すのは (カルマを減らす or ちゃちゃいれ or 他人をおちょくる or so on が目的でなければ) そろそろ潮時かな~と愚考する次第です。
# もっともこの話題の発端は Oliver 氏の伝えるところの
# 教授氏のmath-out [tuxedo.org]な話から始まっているので
# 結局はこの教授氏を説き伏せるのにどちら (規格 or 実装) が
# 有効かという話に帰結したりするのかも。
Re:そんなこと聞いてないんだけど (スコア:1)
「現実の実装」の例の1つを示したつもりだったのだけれど,何を聞こうとしていたのでしょうか?
機械語…の部分が,値を返さずに return するプログラムだとしても,これでは,「main が値を返さないルーチン」として矛盾の無い実行プログラムを生成することはできません. 普通にコンパイルした場合,コンパイラの標準のスタートアップルーチンがリンクされるので,呼び出し側との整合性が取れません. その結果,void main(void) と宣言してコンパイル・実行した時と同じように,「終了ステータスにゴミが返される」という現象が生じるでしょう. そもそも,「動く動かない」だけのの問題だったら,スタートアップルーチンがうんぬん,と言い出さなくても void main(void) でも動きますね.
なんか話がそれてしまってる気もするので,今までのところをまとめてみると
普通はここでシェアードライブラリの実行時リンクと,カーネルと main() のインターフェースを行っている
どっちも (スコア:0)
どっちも、規格にない「ブラックボックス」部分
の実装を利用しているだけでしょう。
ブラックボックスの部分の機能に依存したり、
ブラックボックス自体を書き換えたりして、
動くって言っても、そりゃ動くでしょうけど。
スタートアップルーチンを書き換えちゃうのが、
現実の実装にのっ
Re:どっちも (スコア:1)
そのとおり. C 言語の規格においては,int main(int,char**) の呼び出し元については何も規定されていません. ということは,int main(int,char**) というのは,規格の内と外の境界線に接しているわけです. 現実の実装で int main(int,char**) がどのように反映されているか見てみるには,その境界の外に踏み出す必要があるわけです.
これもそのとおり. main をマシン語で直書きしても,呼び出し元と呼び出し先の引数と戻り値の受渡しについては,状況はなにも変わりません. void main(void) を,このインターフェースに矛盾が生じないよう実装するには,前に書いたように呼び出し元に手を入れる必要があります. つまり,標準的な実装ではないわけです.
で,話をこのスレッドの私の最初の書き込みに戻すと,「main() の引数と戻り値の問題は,実装の面から見ると,スタートアップルーチンとのインターフェースの問題である」というあたりは御理解いただけたようですね. あと,「実際にはどうなってるんだろ.知りたいな」と横から眺めてる,スケベ心満載の御仁にも満足いただけたと思います :-)
Re:みんなで void main (スコア:1)
仮にこの定義を受け入れたとすると、現在のコンピュータでは、関数を表現することは不可能だと思います。
単に引数から戻り値を得るだけの用途でも、時間と空間(記憶域)を消費するという副作用をもちますから。
なので数学的な意味での関数と、コンピュータ用語の関数では、名前が似てるだけで異なるものであるとして扱ったほうがいいように思います。
Re:みんなで void main (スコア:0)
http://haskell.org/
Re:みんなで void main (スコア:1)
排他的事象なのでしょうか?
どっちにせよ、Cの関数の返し値が、数学でいう関数の返し値と
同じものかどうか怪しいっすね。
たんに、数学のほうの返し値の猿真似(???)な書式をCは使える、意味が同じかどうかはさておき、というだけじゃないかと。
コンピュータ言語の関数の定義 (スコア:1)
>ファクション(関数)は副作用がなく、戻り値がある。戻り値の算出に引数以外に依存すべきではない。
プラス、
同じ値の引数で呼び出されたときは、同じ戻り値を返す。
なんてのもあったと思います。
ですから、ランダム関数は、本当は関数ではないと教えられた覚えがあります。(笑)
しかし、コンピュータの数学的モデルであるチューリングマシーン自体が、入力集合と出力集合以外に内部状態とその状態遷移関数を内包しているわけですし、一般的なプログラミング言語の関数を純然たる数学的関数のみで定義するのは、至難の業なのではないでしょうか。
# もっとも、チューリングマシーンは、初期状態と状態遷移関数が固定されてますので、初期状態から全く同じ入力記号列がインプットされれば、必ず同一の出力記号列が得られます。
# そういう意味では、シード値を与えた擬似ランダム関数と同じくらいには、まっとうな“関数”です。(^^;
いまどきのコンピュータ言語の関数の定義って、「戻り値を返せるサブルーティン」くらいの意味であって、数学的な意味合いとは別物と割り切るべきなんでしょうね。
個人的には、コンピュータ言語の関数定義は、ギリギリがんばっても、「同一の内部状態( <-これがクセモノ)と、同一の入力値を与えられたら、同一の出力値を返す」くらいの定義かなと思います。
ちなみに、この定義に則ると、引数で渡されたオブジェクトの内部状態は関数内で変更してはいけないことになります。CONST付き引数の関数のイメージですね。
こんな関数ばかりだったら、使い難くって仕方ないですね。(笑)
<おふとぴ>
そういえば、C言語が一般に広まるときに、「C言語もPascalもAlgol-60系の構造化プログラミング言語だけれど、Pascalは(関数も使える)手続き型言語で、C言語は(手続き的な関数も使える)関数型言語だよ」と云う説明がまかり通っていた記憶があります。
当時、こういう風なツッコミを入れる人が周りに居なかったのが、不思議です。
</おふとぴ>
--- Melloques Les Covdrasey ---
Re:みんなで void main (スコア:0)
しっくりくるけど、int main は、ISO規格だからなぁ。
自分の理想のために、互換性を犠牲にするわけにはいかん。
Re:みんなで void main (スコア:1)
理想は理想ですが、
数学的(なのですね?)な主張に対して「自分の」主張だと言えるのかどうかは、
また別の問題かと。
#ただ、名前の定義を間違っているような気がするんで、
#数学的に正しい主張かどうか?がまず心配ですが。
Re:みんなで void main (スコア:0)
「正しい」の意味が違うでしょう。 (スコア:1)
ただ、それは受け入れがたいんですよね。
#当方に間違い・勘違いがあったらつっこんでください。
gcc (スコア:0)
「教科書の通り打ったら、なんかエラー出るんですけど」