web-dev-qa-db-ja.com

printfを使用してclock_tを印刷する正しい方法は何ですか?

現在、unsigned long longへの明示的なキャストを使用し、%lluを使用して印刷していますが、size_tには%z指定子があるため、clock_tを使用しないのはなぜですか持ってる?

マクロもありません。 x64システム(OSおよびCPU)でsize_tの長さは8バイト(この場合でも%zを提供している)と仮定できますが、clock_tはどうですか?

29
Spidey

完璧な方法はないようです。問題の根本は、_clock_t_が整数または浮動小数点のいずれかである可能性があることです。

clock_tは浮動小数点型にすることができます

BastienLéonardがPOSIXについて 言及しているように(彼に賛成してください)、 C99 N1256 draft 7.23.1/3は次のようにも言っています:

[clock_t is]時刻を表すことができる算術型

および6.2.5/18:

整数型および浮動小数点型は、算術型と総称されます。

また、標準では算術型を整数型または浮動小数点型として定義しています。

CLOCKS_PER_SECで除算する場合は、long doubleを使用します

clock()の戻り値は実装定義であり、それから標準的な意味を引き出す唯一の方法は_CLOCKS_PER_SEC_で除算して秒数を見つけることです:

_clock_t t0 = clock();
/* Work. */
clock_t t1 = clock();
printf("%Lf", (long double)(t1 - t0));
_

次の2つの理由から、これで十分ですが、完璧ではありません。

  • 浮動小数点型の_intmax_t_に類似していないようです: 実装の最大精度の浮動小数点データ型とそのprintf指定子を取得する方法? 浮動小数点型は明日公開され、使用されて実装が中断される可能性があります。

  • _clock_t_が整数の場合、floatへのキャストは、可能な限り最も近いfloatを使用するように明確に定義されています。精度を失う可能性がありますが、絶対値と比較してそれほど重要ではなく、膨大な時間にのみ発生します。 x86の_long int_は、64ビットの有効な80ビットの浮動小数点数で、数百万年単位で表されます。

同様のことを言ったレモナドに賛成票を投じてください

整数であると仮定する場合は、%juとuintmax_tを使用します

_unsigned long long_は現在、可能な最大の標準整数型です:

そのため、可能な限り最大の符号なし整数型に型キャストすることをお勧めします。

_#include <stdint.h>

printf("%ju", (uintmax_t)(clock_t)1);
_

_uintmax_t_は、マシン上で可能な限り最大の整数サイズのサイズを持つことが保証されています。

_uintmax_t_およびそのprintf指定子_%ju_はc99で導入され、たとえばgccはそれらを実装しています。

おまけとして、これは整数型を確実にprintfする方法に関する問題を一度解決します(残念ながら_clock_t_の場合は必ずしもそうではありません)。

ダブルである場合、何がうまくいかない可能性があります:

  • 大きすぎて整数に収まらない場合、未定義の動作
  • 1よりはるかに小さいと0に丸められ、何も表示されません

これらの結果は、整数から浮動小数点への変換よりもはるかに厳しいので、浮動小数点数を使用することをお勧めします。

glibc 2.21では整数です

マニュアルでは、doubleを使用することをお勧めします。

GNU/LinuxおよびGNU/Hurdシステムでは、clock_tはlong intと同等で、CLOCKS_PER_SECは整数値です。しかし、他のシステムでは、clock_tとマクロCLOCKS_PER_SECの両方が整数型または浮動小数点型のいずれかです。上記の例のように、CPU時間の値を2倍にキャストすると、基になる表現が何であっても、算術演算や印刷などの操作が適切かつ一貫して機能することが保証されます。

Glibc 2.21の場合:

  • _clock_t_は_long int_です:

  • Linuxのclock()は_sys_clock_gettime_で実装されます:

    _man clock_gettime_は、GCCで_struct timespec_フィールドを含む_long int_を返すことを示します。

    したがって、基礎となる実装は実際に整数を返します。

こちらもご覧ください

私の知る限り、あなたのやり方は最高です。それ以外で clock_tは実数型の場合があります。

time_tおよびclock_tは整数型または実浮動型でなければなりません。

http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html

12

これはおそらく、クロック刻みが非常に明確な単位ではないためです。秒に変換して、倍精度で印刷できます。

time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC;
printf("%g seconds", seconds);

CLOCKS_PER_SECマクロは、1秒のクロックティック数を表す式に展開されます。

11
lemonad

C規格は、多種多様なアーキテクチャに対応する必要があり、内部クロックタイプが算術であることを除いて、それ以上の保証を行うことはできません。

ほとんどの場合、時間間隔に関心があるため、クロックティックの差をミリ秒に変換します。 unsigned longは、32ビットであっても50日近くの間隔を表すのに十分な大きさなので、ほとんどの場合に十分な大きさである必要があります。

clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;
3
Christoph

1つの方法は、gettimeofday関数を使用することです。この関数を使用して違いを見つけることができます:

unsigned long  diff(struct timeval second, struct timeval first)
{
    struct timeval  lapsed;
    struct timezone tzp;
    unsigned long t;

    if (first.tv_usec > second.tv_usec) {
        second.tv_usec += 1000000;
        second.tv_sec--;
    }

    lapsed.tv_usec = second.tv_usec - first.tv_usec;
    lapsed.tv_sec  = second.tv_sec  - first.tv_sec;
    t = lapsed.tv_sec*1000000 + lapsed.tv_usec;

    printf("%lu,%lu - %lu,%lu = %ld,%ld\n",
           second.tv_sec, second.tv_usec,
           first.tv_sec,  first.tv_usec,
           lapsed.tv_sec, lapsed.tv_usec);

    return t;
}
1
rani