現在、明示的なキャストをunsigned long long
使用して出力していますが、指定子がある%llu
のに、なぜ指定子がないのですか?size_t
%z
clock_t
そのためのマクロすらありません。おそらく、x64 システム (OS と CPU)size_t
では長さが 8 バイトであると想定できます (この場合でも、提供されています) %z
。clock_t
完全な方法はないようです。問題の根本は、clock_t
整数または浮動小数点のいずれかになる可能性があることです。
clock_t は浮動小数点型にすることができます
Bastien Léonard がPOSIX について言及しているように (彼に賛成票を投じてください)、C99 N1256 ドラフト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 を使用するように明確に定義されています。精度が失われる可能性がありますが、絶対値と比較するとそれほど重要ではなく、非常に長い時間しか発生しません。たとえばlong int
、x86 では 80 ビットの float で 64 ビットが有意であり、これは秒単位で数百万年になります。
似たようなことを言ったレモネードに賛成票を投じてください。
整数だと思われる場合は、%ju と uintmax_t を使用してください
unsigned long long
現在可能な最大の標準整数型ですが、
clock_t
それらの 1 つになる可能性があります。したがって、可能な限り最大の符号なし整数型に型キャストするのが最善です。
#include <stdint.h>
printf("%ju", (uintmax_t)(clock_t)1);
uintmax_t
マシン上で可能な最大の整数サイズのサイズを持つことが保証されています。
uintmax_t
およびそのprintf指定子%ju
はc99で導入され、たとえばgccはそれらを実装しています。
おまけとして、これにより、確実にprintf
整数型を作成する方法の問題が完全に解決されます (残念ながら、 の場合は必ずしもそうではありませんclock_t
)。
double の場合、何が問題になる可能性がありますか。
これらの結果は、整数から浮動小数点数への変換よりもはるかに厳しいため、浮動小数点数を使用することをお勧めします。
glibc 2.21 では整数です。
マニュアルには、使用double
する方が良いと書かれています:
GNU/Linux および GNU/Hurd システムでは、clock_t は long int と同等であり、CLOCKS_PER_SEC は整数値です。しかし、他のシステムでは、clock_t とマクロ CLOCKS_PER_SEC の両方が整数型または浮動小数点型のいずれかになります。上記の例のように、CPU 時間の値を double にキャストすると、基礎となる表現が何であれ、算術や印刷などの操作が適切かつ一貫して機能することが保証されます。
glibc 2.21 では:
clock_t
はlong int
:
__clock_t
__CLOCK_T_TYPE
__SLONGWORD_TYPE
long int
clock()
Linux では次のように実装されていsys_clock_gettime
ます。
__clock_gettime
SYSDEP_GETTIME_CPU
SYSCALL_GETTIME
最終的にインライン システム コールを行うsysdeps/unix/sysv/linux/clock_gettime.c呼び出しman clock_gettime
struct timespec
は、GCC にlong int
フィールドが含まれる を返すことを示しています。
したがって、基礎となる実装は実際には整数を返します。
こちらもご覧ください
私の知る限り、あなたのやり方は最高です。ただしclock_t
、実際の型である可能性があります。
time_t
clock_t
整数型または実数浮動小数点型でなければなりません。
http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
おそらく、クロック ティックはあまり明確に定義された単位ではないためです。これを秒に変換して double として出力できます。
time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC;
printf("%g seconds", seconds);
CLOCKS_PER_SEC マクロは、1 秒間のクロック ティック数を表す式に展開されます。
C 標準は、さまざまなアーキテクチャに対応する必要があるため、内部クロック タイプが算術演算であるという事実を除けば、それ以上の保証を行うことはできません。
ほとんどの場合、時間間隔に関心があるので、クロック ティックの差をミリ秒に変換します。Anunsigned long
は、32 ビットであっても 50 日近くの間隔を表すのに十分な大きさであるため、ほとんどの場合に十分な大きさである必要があります。
clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;
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;
}