- - PR -
C の localtime() の引数は混乱を招く。
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-01-14 14:07
と似たコードを書いてsolaris とredhat でgccでコンパイル、実行したら、solarisではcoreを吐いてredhatではなんとなく動いてしまいました。 C言語では、ローカル変数はスタックに領域が確保され、人為的に初期化しない限り、たまたまスタックに有った値になっていると勉強しました。 Solarisもその通りだとしたら、前の処理でスタックにのこった汚れのデータがはいったポインタ変数localtimeに渡しても、たまたま正常に動いて見えただけではないでょうか? スタックの汚れは、前の処理しだいですので、直前の処理を変えてみると結果が変るかも知れません。 試しに struct tm *p_tm; の前に int i; を宣言したらsolarisでもなんとなく動いてしまいました。 | ||||||||
|
投稿日時: 2005-01-14 14:08
ただの思い出ばなしですじゃ。
プログラミング言語C(ANSI−C以前の本)には「標準関数はC言語の一部ではない。」と書かれていたように覚えてるのじゃ。それで、結構驚いたもんじゃ。 #この標準関数とはprintf()とかその手の関数じゃ。 #古い本なんで、まだうちにあるかのう。 だから、わしはCはマクロアセンブラぐらいにしか思ってないんじゃ。 値渡しかどうかという話じゃが、関数の引数は変数の値をスタックにコピーしてから関数に渡されるんじゃ。だから、関数内で引数の値を変えてもスタック中の値が変わるだけで、呼び出し側の元の変数の値の部分は変わらんのじゃ。だから、値渡しじゃと。 で、ポインタが引数ということは、たまたま、その値がポインタだったこいうことじゃ。 ポインタのポインタなんぞ、むずかしくない。渡した値がポインタで、たまたまそれが指す先がポインタということだけじゃ。ポインタが指す実態がintだったり、ぽゐんただったりするだけじゃ。 そうえば、引数にcharを二つ渡して、関数側でそれをintで受け取るなんて極悪なテクニックもあったのう。 プロトタイプもなかったしのう。 [ メッセージ編集済み 編集者: ほろりん 編集日時 2005-01-14 14:19 ] プログラミング言語C(初版)をみつましたじゃ。「標準関数はC言語の一部ではない。」は間違いで、「入出力機能は言語Cの範囲にない」が正確な記述じゃった。すまんかったのう。 [ メッセージ編集済み 編集者: ほろりん 編集日時 2005-01-15 11:09 ] | ||||||||
|
投稿日時: 2005-01-14 14:25
それです。そうなんです。
その類の「すんなり」で私は何度泣かされた事か・・・>Toshi氏 「変数には局所性がある」の法則通り、「たまたま」可も無く不可も無い 領域を Solaris は割り当て易いんでしょうかね。。。 >試しに struct tm *p_tm; の前に int i; を宣言したらsolarisでも >なんとなく動いてしまいました。 やっぱ、この手のバグが顕在化するんは確率なんでしょうかね? ブハハハハ、風情があって「いとおかし」ですな>ほろりん氏 ん〜、情報処理試験問題にすら "Call By Reference" と出てくる 様で、しかも確かに同じアドレスを仮と実で「参照」してるもん やから何の違和感も無く Call By Reference と使い慣れてました が、Java とか C++ には「本物の」 Call By Reference がある んでしょうかね? 確かに、ポインターの指し先を間接的に持つ別のアドレスという だけで、その間接アドレスも値の一つと言われればそうでしょうが、 Java とか C++ との違いがいまいちよく見えません。 「本物の Call By Reference」なるものがどういうものなのか・・・ [ メッセージ編集済み 編集者: コブラ 編集日時 2005-01-14 14:37 ] | ||||||||
|
投稿日時: 2005-01-14 14:35
va_arg なんていう醜悪な関数?もありますね。 関数は所詮他人、値をどう解釈するかは関数次第 [ メッセージ編集済み 編集者: Toshi 編集日時 2005-01-14 14:39 ] | ||||||||
|
投稿日時: 2005-01-14 15:28
ちょっと脇道にそれますが、とりあえず、C++の参照渡しについて参考まで。
関数hogeの結果、表示されるのは、0ではなくて、1です。funcには、xの値0が渡るのではなく、xへの参照が渡ります。なので、func側でxが書き換えられます。これが参照渡しです。Call By Reference。ポインタもアドレスも(表面上は)出てきません。 #ややこしいですが、普通の変数のみならず、ポインタ変数も参照渡しできると思います(多分)。 #その場合、ポインタ変数自身を書き換えることができるのでしょう。。 これは、Cでは実現できません。Cでfunc(x)と書いても、xの値は書き換わりません。ただし、ポインタを使って似たようなことを再現することはできます。
これで、1が表示されます。逆に言うと、Cではアドレスを明示的に渡してあげなければ、関数側に変数の値を書き換えさせることはできません。(返り値以外では) 以上参考まで。。細かい解説は省略です。。本筋の議論はまた後ほど。。 | ||||||||
|
投稿日時: 2005-01-14 15:29
こんにちは。
本物かどうかはわかりませんが、例えば言語レベルで参照渡しをサポートしているかどうかを基準にしてみるというのもあると思います。 VisualBasicやPASCALなどはサポートしていますよね。VBですとデフォルトが参照渡しで「by val」を付けると値渡しでしたっけ。 | ||||||||
|
投稿日時: 2005-01-14 15:45
どぅさんの、
これは、もし x が 構造体ならば、構造体の先頭アドレスを渡してやる訳で、 time(); とか localtime_s(); の引数でも同じではないのですか? ちょっとそこら辺は曖昧なもんで。 | ||||||||
|
投稿日時: 2005-01-14 18:11
これだけではなくて、C++の"参照引数(&)"には、 ポインタとの決定的な違いがあります。 『引数型の"実体のある変数"しか渡せない』という制限です。 引数がポインタ型なら、 func(NULL); とか func(777);//適当 なんてことが出来てしまいますが、 参照型引数には、なんらかの実体のある変数 を渡さないとコンパイルエラーになります。 参照先が不正なアドレスで落ちる、ということが防げるわけです。 [ メッセージ編集済み 編集者: ナキヲ 編集日時 2005-01-14 18:15 ] |