- - PR -
C の localtime() の引数は混乱を招く。
投稿者 | 投稿内容 | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-01-14 18:32
わしは引退した身じゃて、ジャヴァとかしぃぷらぷらとかいう新型の目的指向型電脳用言語は知らんが、住所指示変数(ぽゐんたぁ)も参照渡しができないとおかしいですじゃ。 さっきも言ったんじゃが、住所指示変数は、単に記憶領域の住所が入っているだけで普通の変数と変わらないはずじゃ。何もややこしいことはないはずじゃ。 | ||||||||||||||||||||
|
投稿日時: 2005-01-14 21:59
C++の参照渡しへのフォローどうもです。>みなさま
構造体も普通のint型の変数も、関数への受け渡しにおいては扱いは同じです。(配列はちと違います) すんません、time()関数についてだけ、記述します。プロトタイプはこんな感じでしょうか。。 time_t time(time_t *tptr) です。これの仕様は、 1:引数には、ある領域のアドレスをもらう。 2:現在の時刻を表すtime_t型の値を返り値として返す。 3:引数で与えられたアドレスの指す領域に、time_t型の2と同じ値を書き込む です。今は引数が話題になっているので、返り値のことは無視しましょう。とすると、普通、これはこのように呼び出します。
これで、変数timeValに、現在時刻を表すある値が書き込まれます。なぜなら、time()関数は、&timeValという記述によって、timeValの「アドレス」を教えてもらったからです。逆に言うと、time関数は、与えられたアドレスに書き込んだだけで、そこがtimeValという変数の領域だということには全然知りません。 また、こう書くこともできるでしょう。同じことです。
こうしても、変数timeValに現在時刻を表す値が書き込まれます。なぜなら、time()関数は、p_timeという記述によって、timeValのアドレスを教えてもらったからです。time関数側では、timeValという変数の存在も、p_timeというポインタ変数の存在も見えません。分かるのは「アドレス」だけです。結局これによって変更されるのは、timeValの値であって、p_timeの値は変らないという点に注意してください。 あたり前ですが、参照渡しのできないCでは、次のように書いても、timeValに値をもらうことはできません。
timeValの値は全然変化しないでしょう。(まぁ引数の型がちがってますが^^;) さて、ここでこのスレッドの一番最初の話にもどります。(関数は違うけど^^;)
こうしたときに、何が起こるのでしょうか?これはまずいコーディングですが、なぜまずいのでしょうか? まず、p_timeの値は書き換わりません。値渡しなので、引数は影響を受けないのです。 time()関数側から見ると、アドレスが渡るとしか思っていません。p_timeに書かれた値が、time関数に渡されます。どんな値が渡されるのでしょうか?p_timeが格納されている領域のアドレスでしょうか?そうではないですね。p_timeが格納されている領域のアドレスは&p_timeです。ではどんな値でしょうか?p_timeにはどんな値が入っているのでしょうか? それは、p_timeを宣言して領域確保したときに「偶然その領域に書いてあった値」ですね。たとえば、以前の名残から7と書いてあったら、p_timeには7という値が入っています。つまりp_timeは7番地を指している。7番地の領域って、どんな領域でしょうか?さぁ分かりません^^;しかし、time()関数はそんなことは知りません。7という値を受け取り、それをアドレスだと思うだけです。なので、time()関数は7番地にアクセスし、7番地にtime_t型の値を書き込みます。その際、問答無用に書き込みます。領域なんて気にしません。確保もしません。 この場合、その領域の状況しだいで、セグメンテーションフォールトが発生することがあります。書き込まれる領域のアドレスは、「p_timeの領域に偶然書かれていた値」番地です。 難しい話ではありません。適当なアドレスを関数に渡せば、関数は知らずにその適当なアドレス領域にアクセスして、もしかしたらセグメンテーションフォールトを起こすし、もしかしたらうまく動きます。 こういうのは、普通バグといいます。これを避けるためには、アドレスを渡す際には、そのアドレスの先がちゃんと確保されていることを確認すること。それから、補助的ですが有効な手段として、コンパイラの警告レベルを上げて初期化漏れをなくすこと。です。 別にポインタに限った話ではありません。宣言しただけで正しい値を代入していない変数を関数に渡す(←これは値渡しという意味ですよ)というのはバグの元です。 以上です。 | ||||||||||||||||||||
|
投稿日時: 2005-01-15 09:51
おもしろい、状況を正確に理解する 手段としてマシンの 意味論で説明したほうが
言語が作り出した「変数・引数渡し・ポインタ・・・」よりいいなんて。 C 言語の概念・意味の抽象度が中途半端なのかもしれないが。 型のある世界にもかかわらず、型破壊光線がいろいろあると言うこと。 [ メッセージ編集済み 編集者: MMX 編集日時 2005-01-31 10:25 ] | ||||||||||||||||||||
|
投稿日時: 2005-01-15 11:40
この手の、顕在化しないバグについては、今のところ Warning レベルを上げるとか
Purify とかのツールを使うかの何れか、という事になるでしょうか。 そこが明らかになっただけでも私にとっては利益というべきです。 いや、皆さんありがとうございました。 後、ナキヲさんの、"C++ の「参照」は実体のある変数でないとエラー"、 >これだけではなくて、C++の"参照引数(&)"には、 >ポインタとの決定的な違いがあります。 >『引数型の"実体のある変数"しか渡せない』という制限です。 >引数がポインタ型なら、 >func(NULL); >とか >func(777);//適当 >なんてことが出来てしまいますが、 >参照型引数には、なんらかの実体のある変数 >を渡さないとコンパイルエラーになります。 >参照先が不正なアドレスで落ちる、ということが防げるわけです。 これは目から鱗が落ちました。 _________________ 日本の中心で、オフを叫ぶ(@名古屋)。 ご意見募集中! コブラ | ||||||||||||||||||||
|
投稿日時: 2005-01-16 21:52
まぁ、お礼という程のものでもないですが、ささやかながら
こんなモンでも・・・ http://202.226.153.50/cobra/public_html/ieri/images/episode3.mov どうぞ。私は、20世紀フォックスに貢献します。 | ||||||||||||||||||||
|
投稿日時: 2005-08-24 02:32
こっちの方が行数も少ないし単純なので、こっちにしましょう。
[ メッセージ編集済み 編集者: コブラ 編集日時 2005-12-26 20:43 ] | ||||||||||||||||||||
|
投稿日時: 2005-08-24 21:15
コブラちゃんがこんなことを書くなんて。
面倒なので中身のコードは見てません。 // 第一引数: *tm // 型: tm 構造体へのポインター そりゃポインターだってことはわかるよ。 // 出力 : *tm // 型: tm 構造体へのポインター だからなにがでてくるんだよそれ。 // 戻り値 : 論理型 // TRUE : 1 // FALSE: 0 そんなことは知ってるよ。 | ||||||||||||||||||||
|
投稿日時: 2005-08-30 12:36
これまでの経緯をちゃんと把握してから書き込みましょう。
|