Есть ли способ получить 64-битный time_t в 32-битной программе в Linux
На Windows я могу позвонить:
_time32(__time32_t); // to get 32bit time_t
_time64(__time64_t); // to get 64bit time_t
(как в 32, так и в 64-битных программах)
Есть ли способ сделать это в Linux (компиляция с GCC)?
4 ответа
Видимо, нет, это невозможно. Для начала есть только один time()
функции в Linux нет time32()
или же time64()
,
Пройдя некоторое время на поиске, я вижу, что это не ошибка libc, но виновником на самом деле является ядро.
Для того, чтобы libc мог извлечь текущее время, он должен выполнить системный вызов для него: ( Source)
time_t time (t) time_t *t;
{
// ...
INTERNAL_SYSCALL_DECL (err);
time_t res = INTERNAL_SYSCALL (time, err, 1, NULL);
// ...
return res;
}
Системный вызов определяется как: ( Источник)
SYSCALL_DEFINE1(time, time_t __user *, tloc)
{
time_t i = get_seconds();
// ...
return i;
}
Функция get_seconds()
возвращает unsigned long
Вот так: ( Источник)
unsigned long get_seconds(void)
{
struct timekeeper *tk = &timekeeper;
return tk->xtime_sec;
}
А также timekeeper.xtime_sec
на самом деле 64-битный: ( источник)
struct timekeeper {
// ...
/* Current CLOCK_REALTIME time in seconds */
u64 xtime_sec;
// ...
}
Теперь, если вы знаете свой C, вы знаете, что размер unsigned long
на самом деле зависит от реализации. На моей 64-битной машине она 64-битная; но на моей 32-битной машине он 32-битный. Возможно, он может быть 64-битным в некоторых 32-битных реализациях, но нет никакой гарантии.
С другой стороны, u64
всегда 64-битный, поэтому в самом ядре ядро отслеживает время в 64-битном типе. Почему тогда он возвращает это как unsigned long
, который не гарантированно будет 64-битным, вне моего понимания.
В конце концов, даже если libc's заставит time_t
для хранения 64-битного значения это ничего не изменит.
Вы можете глубоко привязать свое приложение к ядру, но я не думаю, что оно того стоит.
Во многих ответах выше говорилось, что это невозможно, но это совершенно неверно. В то время это было невозможно, но люди годами говорили об этом. Наконец, в ядре Linux 5.1 была добавлена поддержка 64-битного времени на 32-битных платформах с добавлением нового *time64
системные вызовы. Посмотрите на эту таблицу, и вы увидите, что эти системные вызовы недоступны ни на одной 64-битной платформе. Теперь, если вы пишете код для 32-битных систем, вы можете вызватьclock_gettime64
напрямую (из встроенной сборки или C с syscall()
) чтобы получить текущее время
Однако после этого вы полностью предоставлены сами себе. Если вам нужна полная поддержка пользовательского пространства, вы должны использовать Linux 5.6 или выше вместе с musl 1.2+ или glibc 2.32+. Просто перестройте свой код иtime_t
станет 64-битным
Все пользовательское пространство должно быть скомпилировано с 64-битной
time_t
, который будет поддерживаться в следующих выпусках musl-1.2 и glibc-2.32 вместе с установленными заголовками ядра из linux-5.6 или выше.Приложения, которые напрямую используют интерфейсы системных вызовов, необходимо портировать для использования системных вызовов time64, добавленных в linux-5.1, вместо существующих системных вызовов. Это влияет на большинство пользователей
futex()
а такжеseccomp()
а также языки программирования, у которых есть собственная среда выполнения, не основанная на libc.
Чтобы получить больше информации
Нет time64()/time32()
Функция входит в стандартные библиотеки.
нет time32_t/time64_t
Определения предусмотрены в стандартных заголовках.
time_t
определяется в time.h
как typedef __time_t time_t
;
После длинной цепочки переопределений вы обнаружите, что __time_t
определяется как 32-разрядный на 32-разрядных компьютерах и 64-разрядный на 64-разрядных компьютерах.
Используйте эту библиотеку: https://github.com/evalEmpire/y2038
Целью этого проекта является предоставление замены POSIX time.h, которая будет работать на машинах, которые имеют 32-битный time_t, но не страдают от ошибки 2038. Это позволит программистам на C быть безопасными для 2038 без необходимости переписывать их программное обеспечение на новый интерфейс. Это происходит при использовании базы данных системного часового пояса.
Если вам это действительно нужно, почему бы не сделать свой собственный?
typedef int32_t my_time32;
typedef int64_t my_time64;
my_time32 get_mytime32() {
if (sizeof(time_t) == sizeof(my_time32))
return time(NULL);
else {
/* Check for overflow etc. here... */
return (my_time32)(time(NULL));
}
}
И аналогично для get_mytime64()
,
Если вы не заботитесь о переполнении, просто return time(NULL);
будет работать для обеих функций благодаря неявным преобразованиям чисел в Си.