В настоящее время я использую явное преобразование в unsigned long long
и используя %llu
для его печати, но поскольку size_t
имеет спецификатор %z
, почему clock_t
не имеет одного?
Для этого нет даже макроса. Возможно, я могу предположить, что в x64-системе (ОС и ЦП) size_t
длина 8 байтов (и даже в этом случае они предоставили %z
), но как насчет clock_t
?
Ответ 1
Кажется, нет идеального пути. Корень проблемы состоит в том, что clock_t
может быть целым или плавающим.
clock_t может быть типом с плавающей точкой
Как Bastien Léonard упоминает для POSIX (перейдите вверх), C99 N1256 draft 7.23.1/3 также говорит, что:
[clock_t is] арифметические типы, способные представлять время
и 6.2.5/18:
Целочисленные и плавающие типы совместно называются арифметическими типами.
а стандарт определяет арифметический тип как целые числа, так и типы с плавающей запятой.
Если вы разделите CLOCKS_PER_SEC, используйте длинный двойной
Возвращаемое значение clock()
определяется реализацией, и единственный способ получить стандартное значение из него состоит в том, чтобы разделить на CLOCKS_PER_SEC
, чтобы найти количество секунд:
clock_t t0 = clock();
/* Work. */
clock_t t1 = clock();
printf("%Lf", (long double)(t1 - t0));
Это достаточно хорошо, хотя и не идеально, по двум следующим причинам:
-
для типов с плавающей точкой не существует аналога intmax_t
: Как получить максимальный тип данных с плавающей запятой и его спецификатор printf? Так, если завтра появится более крупный тип с плавающей точкой, его можно будет использовать и прервать вашу реализацию.
-
если clock_t
является целым числом, метод cast to float корректно определен, чтобы использовать ближайший поплавок. Вы можете потерять точность, но это не имеет большого значения по сравнению с абсолютной величиной и будет происходить только в течение огромного количества времени, например. long int
в x86 - это 80-битный поплавок с 64-битным значащим значением, который составляет миллионы лет в секундах.
Перейдите в лимонад, который сказал что-то подобное.
Если вы считаете, что это целое число, используйте% 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
).
Что может пойти не так, если он был двойным:
- если слишком большой, чтобы вписаться в целое число, undefined поведение
- намного меньше 1, округляется до 0 и вы ничего не увидите
Поскольку эти последствия намного более жесткие, чем целочисленное преобразование с плавающей точкой, использование float, вероятно, является лучшей идеей.
В glibc 2.21 это целое число
В руководстве говорится, что использование double
- лучшая идея:
В системах GNU/Linux и GNU/Hurd clock_t эквивалентен long int, а CLOCKS_PER_SEC - целочисленное значение. Но в других системах, как clock_t, так и макрос CLOCKS_PER_SEC могут быть либо целыми, либо с плавающей точкой. Приведение значений времени CPU в два раза, как в приведенном выше примере, гарантирует, что операции, такие как арифметика и печать, работают правильно и последовательно независимо от того, что представляет собой основное представление.
В glibc 2.21:
-
clock_t
long int
:
-
clock()
в Linux реализована с помощью sys_clock_gettime
:
man clock_gettime
, сообщает нам, что он возвращает struct timespec
, который в GCC содержит поля long int
.
Итак, основная реализация действительно возвращает целые числа.
См. также
Ответ 2
Возможно, это связано с тем, что тактовая частота не является очень четкой единицей. Вы можете преобразовать его в секундах и распечатать его как double:
time_in_seconds = (double)time_in_clock_ticks / (double)CLOCKS_PER_SEC;
printf("%g seconds", seconds);
Макрос CLOCKS_PER_SEC расширяется до выражения, представляющего количество тактов синхронизации за секунду.
Ответ 3
Насколько я знаю, лучший способ - это то, как вы делаете. За исключением того, что clock_t
может быть реальным типом:
time_t
и clock_t
должны быть целыми или реальными плавающими типами.
http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
Ответ 4
Стандарт C должен сочетать в себе множество архитектур, что делает невозможным любые дальнейшие гарантии, кроме того, что внутренний тип часов является арифметическим.
В большинстве случаев вас интересуют временные интервалы, поэтому я бы конвертировал разницу в тактовых импульсах в миллисекундах. unsigned long
достаточно большой, чтобы представлять интервал почти 50 дней, даже если его 32-разрядный, поэтому он должен быть достаточно большим для большинства случаев:
clock_t start;
clock_t end;
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;
Ответ 5
Одним из способов является использование функции 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;
}