Ответ 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
в настоящее время является наибольшим стандартным целочисленным типом:
- в будущем может появиться больший
- стандарт уже явно допускает более крупные определенные типы реализации (kudos to @FUZxxl) и
clock_t
может быть одним из них
поэтому лучше всего прибегнуть к максимальному максимальному целочисленному типу без знака:
#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
:- time/time.h устанавливает его в
__clock_t
- bits/types.h устанавливает его в
__CLOCK_T_TYPE
- bits/typesizes.h устанавливает его на
__SLONGWORD_TYPE
- bits/types.h устанавливает его в
long int
- time/time.h устанавливает его в
-
clock()
в Linux реализована с помощьюsys_clock_gettime
:- sysdeps/unix/sysv/linux/clock.c вызывает
__clock_gettime
- sysdeps/unix/clock_gettime.c вызывает
SYSDEP_GETTIME_CPU
- sysdeps/unix/sysv/linux/clock_gettime.c вызывает
SYSCALL_GETTIME
, который, наконец, делает встроенный системный вызов
man clock_gettime
, сообщает нам, что он возвращаетstruct timespec
, который в GCC содержит поляlong int
.Итак, основная реализация действительно возвращает целые числа.
- sysdeps/unix/sysv/linux/clock.c вызывает
См. также