Відповіді:
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 року .
time_t
в структурі даних на диску може статися. Однак, оскільки файлові системи часто читаються іншими операційними системами, було б нерозумно визначити файлову систему на основі таких типів, що залежать від реалізації. Наприклад, одна і та ж файлова система може бути використана як для 32-бітної, так і для 64-бітової систем і time_t
може змінювати розмір. Таким чином, файлові системи потрібно визначити точніше ("32-бітове підписане ціле число, даючи кількість секунд з початку 1970 року в UTC"), а не як time_t
.
time.h
вмісту. Ця стаття посилається на cppreference.com, але цитованого контенту ніде не знайдено…
time_t
підписання, є неправильним. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… диктує, що різні речі повинні бути "підписаним цілим числом" або "непідписаним цілим числом", але про time_t
нього йдеться лише про те, що "має бути цілим числом" . Реалізація може зробити time_t
без підпису та все-таки сумісною з POSIX.
[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
typedef __int32_t __time_t;
і typedef __time_t time_t;
в, і в а FreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386
. Ваші результати явно встановлені таким чином у Linux (принаймні, на 2.6.32-5-xen-amd64 від Debian).
__time_t
а не time_t
знаходити базовий тип time_t
? Пропустіть крок?
typedef __time_t time_t;
, необхідне також вивчення навколишнього коду, щоб гарантувати, що typedef насправді використовувався, а не є лише частиною умовної компіляції. typedef long time_t;
можливо, їх теж знайшли.
Стандарти
Вільям Брендль цитував Вікіпедію, але я віддаю перевагу це з вуст коня.
Стандартний проект 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, оскільки вхід походить від stdin, який не має розширення файлу.-include file
: "Обробити файл так, ніби" #include "файл" "з'явився як перший рядок файлу первинного джерела."-
: вхід від stdingcc -E -xc -include time.h /dev/null | grep time_t
Відповідь, безумовно, залежить від впровадження. Щоб остаточно дізнатися для своєї платформи / компілятора, просто додайте цей вихід десь у свій код:
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 (по каналу зв'язку). Це викликає проблеми впорядкування байтів, але це інша тема.
Щоб відповісти на запит paxdiablo, я б сказав, що він надрукував "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
Оператор друкує фіксовану рядок «Рік є: 19» , за яким слід нулями рядок з «років починаючи з 1900 року » (визначення tm->tm_year
). У 2000 році, очевидно, це значення 100. "%02d"
колодки з двома нулями, але не врізається, якщо довше двох цифр.
Правильний спосіб (змінити лише останній рядок):
printf ("Year is: %d\n", local_date_time.tm_year + 1900);
Нове запитання: що обґрунтовує це мислення?
%zu
специфікатор формату для size_t
значень формату (як отримано sizeof
), оскільки вони не підписані ( u
) та довжини size_t ( z
) ·
printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
та уникати z
проблеми.
У візуальній студії 2008 вона встановлюється за замовчуванням, __int64
якщо ви не визначите _USE_32BIT_TIME_T
. Вам краще просто зробити вигляд, що ви не знаєте, як це визначено, оскільки він може (і буде) змінюватися від платформи до платформи.
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;
long int
скрізь. Дивіться stackoverflow.com/questions/384502/…
Це 32-бітний цілочисельний підписаний тип на більшості застарілих платформ. Однак це призводить до того, що ваш код страждає від 2038 року помилки . Тож сучасні бібліотеки С повинні визначати, що це замість цього 64-бітний підписаний int, що є безпечним протягом декількох мільярдів років.
Як правило, ви знайдете ці основні типи для реалізації, що стосуються gcc, у каталозі bits
або asm
заголовку. Для мене це /usr/include/x86_64-linux-gnu/bits/types.h
.
Ви можете просто зіткнути або використати виклик препроцесора, як запропоновано Quassnoi щоб побачити, який конкретний заголовок.
Що в кінцевому підсумку є type_t typedef?
Надійний код не байдуже, що це за тип.
Вид 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);
double difftime(time_t time1, time_t time0)
рівномірний підхід віднімання.
time_t
- це лише typedef
8 байт ( long long/__int64
), які розуміють усі компілятори та ОС. Ще в ті часи це було лише для long int
(4 байти), але не зараз. Якщо ви подивитесь на time_t
в, crtdefs.h
ви знайдете обидві реалізації, але ОС використовуватиме long long
.
long int
.