ページ 11

clock関数

Posted: 2009年4月07日(火) 11:20
by
こんにちは。いつもお世話になっています。
C言語は初心者で、現在テキストを参考にしながら進めています。
WindowsのVistaを使っています。

今回の質問は、clock関数を用いて、xミリ秒経過するのを待つ関数に関してです。
int sleep( unsigned long x )
{
    clock_t c1 = clock(), c2;
    do {
        if ( ( c2 = clock() ) == ( clock_t ) -1 ) {
            return ( 0 );
        }
    } while ( 1000.0 * ( c2 - c1 ) / CLOCKS_PER_SEC < x );
    return ( 1 );
}
・( clock_t ) -1 というのはclock_t型でキャストされた-1とテキストにあったのですが、-1はどういう意味があるのでしょうか?よろしくお願いします。

Re:clock関数

Posted: 2009年4月07日(火) 11:31
by 御津凪
clock 関数の仕様では、関数が失敗すると -1 を返します。
上記のコードの場合、 clock 関数の戻り値を取得した値( c2 )と比較し、一致していれば処理が失敗したと判断しています。

Re:clock関数

Posted: 2009年4月07日(火) 12:08
by
解答ありがとうございます。

すいません、もう一つ質問がありました。
・どうして、1000.0を掛けるのでしょうか?

Re:clock関数

Posted: 2009年4月07日(火) 12:22
by 御津凪
clock 関数は文字通りクロック時間を返すので、 CLOCKS_PER_SEC を使って秒単位に変換します。
second = ( c2 - c1 ) / CLOCKS_PER_SEC; // 秒単位に変換
今回必要としているのはミリ秒なので、
一度経過クロック時間に 1000 を掛けてから CLOCKS_PER_SEC で割ることにより、
単位をミリ秒に変換しています。
milli_second = 1000 * ( c2 - c1 ) / CLOCKS_PER_SEC; // ミリ秒単位に変換
ちなみに上の式の計算順序では小数点以下は計算に影響がないため、
1000 にしても計算結果は変わりません。

Re:clock関数

Posted: 2009年4月07日(火) 15:46
by
めっちゃ、理解出来ました。
ありがとうございました。

Re:clock関数

Posted: 2009年4月08日(水) 08:37
by toyo
xの値によっては1000 * ( c2 - c1 )がclock_t型をオーバーフローする可能性を考えてdouble型にしているのでは
CLOCKS_PER_SECが1000000ならその可能性も高くなりますし

Re:clock関数

Posted: 2009年4月08日(水) 14:33
by 御津凪
> xの値によっては1000 * ( c2 - c1 )がclock_t型をオーバーフローする可能性を考えてdouble型にしているのでは

そういえば CLOCKS_PER_SEC の値を見ていませんでした。
1000000 なら、2147 ミリ秒を超えたらオーバーフローしますね。
(clock_t が long 型の場合)
milli_second = (unsigned long)(1000ULL * ( c2 - c1 ) / CLOCKS_PER_SEC);
で、 64bit で計算しても回避可能ですね。

Re:clock関数

Posted: 2009年4月08日(水) 18:18
by
>1000000 なら、2147 ミリ秒を超えたらオーバーフローしますね。
これって、どういう意味ですか?

Re:clock関数

Posted: 2009年4月08日(水) 18:44
by 御津凪
32bit符号付き(long型)の場合、 1000000 * 2147 では、
2147000000 と正しく計算されるのですが、
1000000 * 2148 となると、
-2146967296 となってしまいます。(これがオーバーフロー)

これは、最初に提示されている sleep 関数で 1000.0 を 1000 にした場合
0 ~ 2147 ミリ秒までしか正しく処理されないということになります。
もし、2148 以上を指定した場合は、オーバーフローで負数になっているため、
2148 ミリ秒までしか待ってくれません。

そのため、 2147 ミリ秒以上待つ可能性がある場合は提示されている関数のままの状態か、
経過時間の計算時に 64bit 整数として計算するように直すといいと思います。