Что такое time_t в конечном итоге typedef? - PullRequest
181 голосов
/ 23 января 2009

Я искал свой ящик с Linux и увидел этот typedef:

typedef __time_t time_t;

Но я не смог найти определение __time_t.

Ответы [ 10 ]

158 голосов
/ 23 января 2009

Статья time_t в Википедии проливает свет на это. Суть в том, что тип time_t не гарантируется в спецификации C.

Тип данных time_t является типом данных в библиотека ISO C, определенная для хранения значения системного времени. Такие значения вернулся из стандарта time() библиотечная функция. Этот тип typedef, определенный в стандарте заголовок. ISO C определяет time_t как арифметический тип, но делает не указывать какой-либо конкретный тип , диапазон, разрешение или кодировка для него. Также не определены значения арифметические операции, применяемые ко времени значения.

Unix и POSIX-совместимые системы реализуют тип time_t в виде signed integer (обычно 32 или 64 бит) который представляет количество секунд с начала эпохи Unix : полночь UTC от 1 января 1970 года (не считая високосные секунды). Некоторые системы правильно обрабатывать отрицательные значения времени, а другие нет. Системы, использующие 32-битный time_t тип восприимчив к проблема 2038 года .

101 голосов
/ 23 января 2009

[root]# cat time.c

#include <time.h>

int main(int argc, char** argv)
{
        time_t test;
        return 0;
}

[root]# gcc -E time.c | grep __time_t

typedef long int __time_t;

Это определено в $INCDIR/bits/types.h через:

# 131 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/typesizes.h" 1 3 4
# 132 "/usr/include/bits/types.h" 2 3 4
19 голосов

Стандарты

Уильям Брендель цитирует Википедию, но я предпочитаю ее изо рта лошади.

C99 N1256 стандартная тяга 7.23.1 / 3 «Составляющие времени» говорит:

Объявленные типы: size_t (описан в 7.17) clock_t и time_t, которые являются арифметическими типами, способными представлять времена

и 6.2.5 / 18 «Типы» говорит:

Целочисленные и плавающие типы вместе называются арифметическими типами.

POSIX 7 sys_types.h говорит:

[CX] time_t должен быть целочисленным типом.

, где [CX] равно , определено как :

[CX] Расширение до стандарта ISO C.

Это расширение, потому что оно дает более сильную гарантию: плавающие точки отсутствуют.

gcc однострочный

Нет необходимости создавать файл, как упомянуто от Quassnoi :

echo | gcc -E -xc -include 'time.h' - | grep time_t

В Ubuntu 15.10 GCC 5.2 две верхние строки:

typedef long int __time_t;
typedef __time_t time_t;

Распределение команд с некоторыми цитатами из man gcc:

  • -E: «Остановитесь после этапа предварительной обработки; не запускайте компилятор должным образом.»
  • -xc: Укажите язык C, поскольку входные данные поступают из стандартного ввода без расширения файла.
  • -include file: «Файл процесса, как если бы« #include «файл» »появился в первой строке первичного исходного файла."
  • -: ввод со стандартного ввода
12 голосов
/ 13 июня 2012

Ответ определенно зависит от реализации. Чтобы точно определить вашу платформу / компилятор, просто добавьте этот вывод где-нибудь в вашем коде:

printf ("sizeof time_t is: %d\n", sizeof(time_t));

Если ответ 4 (32 бита) и ваши данные выходят за пределы 2038 , то у вас есть 25 лет для переноса кода.

С вашими данными все будет в порядке, если вы сохраните ваши данные в виде строки, даже если это что-то простое, например:

FILE *stream = [stream file pointer that you've opened correctly];
fprintf (stream, "%d\n", (int)time_t);

Тогда просто прочитайте его обратно тем же способом (fread, fscanf и т. Д. В int), и у вас будет время смещения вашей эпохи. Подобный обходной путь существует в .Net. Я без проблем передаю 64-битные числа эпох между системами Win и Linux (через канал связи). Это поднимает проблемы с порядком байтов, но это уже другая тема.

Чтобы ответить на запрос Паксдиабло, я бы сказал, что он напечатал «19100», потому что программа была написана таким образом (и я признаю, что сделал это сам в 80-х):

time_t now;
struct tm local_date_time;
now = time(NULL);
// convert, then copy internal object to our object
memcpy (&local_date_time, localtime(&now), sizeof(local_date_time));
printf ("Year is: 19%02d\n", local_date_time.tm_year);

Оператор printf печатает фиксированную строку «Year is: 19», за которой следует строка, дополненная нулями, с «Years from 1900» (определение tm->tm_year). В 2000 году это значение, очевидно, равно 100. "%02d" дополняется двумя нулями, но не усекается, если длиннее двух цифр.

Правильный путь (изменить только на последнюю строку):

printf ("Year is: %d\n", local_date_time.tm_year + 1900);

Новый вопрос: в чем причина этого мышления?

7 голосов
/ 23 января 2009

В Visual Studio 2008 по умолчанию используется значение __int64, если не задано значение _USE_32BIT_TIME_T. Вам лучше всего лишь притвориться, что вы не знаете, как оно определяется, поскольку оно может (и будет) меняться от платформы к платформе.

5 голосов
/ 24 августа 2014

time_t относится к типу long int на 64-разрядных компьютерах, в противном случае это long long int.

Вы можете проверить это в следующих заголовочных файлах:

time.h: /usr/include
types.h и typesizes.h: /usr/include/x86_64-linux-gnu/bits

(Приведенные ниже операторы не являются друг за другом. Их можно найти в соответствующем заголовочном файле с помощью Ctrl + f search.)

1) В time.h

typedef __time_t time_t;

2) В types.h

# define __STD_TYPE     typedef  
__STD_TYPE __TIME_T_TYPE __time_t;  

3) В typesizes.h

#define __TIME_T_TYPE       __SYSCALL_SLONG_TYPE  
#if defined __x86_64__ && defined __ILP32__  
# define __SYSCALL_SLONG_TYPE   __SQUAD_TYPE  
#else
# define __SYSCALL_SLONG_TYPE   __SLONGWORD_TYPE
#endif  

4) Опять в types.h

#define __SLONGWORD_TYPE    long int
#if __WORDSIZE == 32
# define __SQUAD_TYPE       __quad_t
#elif __WORDSIZE == 64
# define __SQUAD_TYPE       long int  

#if __WORDSIZE == 64
typedef long int __quad_t;  
#else
__extension__ typedef long long int __quad_t;
4 голосов
/ 23 января 2009

Это 32-разрядное целое число со знаком на большинстве устаревших платформ. Однако это приводит к тому, что ваш код страдает от ошибки year 2038 . Поэтому современные библиотеки C должны определять его как 64-разрядное целое число со знаком, что безопасно в течение нескольких миллиардов лет.

3 голосов
/ 21 февраля 2012

Обычно вы найдете эти базовые специфичные для реализации typedefs для gcc в каталоге заголовков bits или asm. Для меня это /usr/include/x86_64-linux-gnu/bits/types.h.

Вы можете просто выполнить grep или использовать вызов препроцессора, подобный предложенному Quassnoi , чтобы увидеть, какой именно заголовок.

1 голос
/ 05 января 2018

К чему в конечном итоге относится type_t type_t?

Надежный код не заботится о типе.

C видов time_t будет реальным типом как double, long long, int64_t, int и т. Д.

Это может быть даже unsigned, так как возвращаемые значения из многих функций времени, указывающих на ошибку, не -1, а (time_t)(-1) - этот вариант реализации необычен.

Дело в том, что тип "необходимость знать" встречается редко. Код должен быть написан, чтобы избежать необходимости.


Тем не менее, обычная «необходимость знать» возникает, когда код хочет напечатать необработанный time_t. Приведение к самому широкому целому типу будет соответствовать большинству современных случаев.

time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or 
printf("%lld", (long long) now);

Приведение к double или long double также будет работать, но может обеспечить неточный десятичный вывод

printf("%.16e", (double) now);
0 голосов
/ 28 октября 2011

time_t - это просто typedef для 8 байт (long long/__int64), что понимают все компиляторы и ОС. Раньше это было только для long int (4 байта), но не сейчас. Если вы посмотрите на time_t в crtdefs.h, вы найдете обе реализации, но ОС будет использовать long long.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...