Der time_tDatentyp ist ein Datentyp in der ISO C-Bibliothek, der zum Speichern von Systemzeitwerten definiert ist. Solche Werte werden von der Standardbibliotheksfunktion zurückgegeben time()
. Dieser Typ ist ein typedef, der im Standardheader definiert ist. ISO C definiert time_t als einen arithmetischen Typ, gibt jedoch keinen bestimmten Typ , Bereich, Auflösung oder Codierung dafür an. Nicht spezifiziert sind auch die Bedeutungen von arithmetischen Operationen, die auf Zeitwerte angewendet werden.
Unix- und POSIX-kompatible Systeme implementieren den time_tTyp als signed
integer(normalerweise 32 oder 64 Bit breit), der die Anzahl der Sekunden seit Beginn der Unix-Epoche darstellt : Mitternacht UTC vom 1. Januar 1970 (ohne Schaltsekunden). Einige Systeme verarbeiten negative Zeitwerte korrekt, andere nicht. Systeme, die einen 32-Bit- time_tTyp verwenden, sind für das Problem des Jahres 2038 anfällig .
Beachten Sie jedoch, dass time_t-Werte normalerweise nur im Speicher und nicht auf der Festplatte gespeichert werden. Stattdessen wird time_t zur dauerhaften Speicherung in Text oder ein anderes portables Format konvertiert. Das macht das Y2038-Problem nicht wirklich zu einem Problem.
11
@Heath: Auf einem bestimmten System, auf dem dieselben Personen das Betriebssystem und die C-Bibliothek erstellen, kann die Verwendung time_tin der Datenstruktur auf der Festplatte vorkommen. Da Dateisysteme jedoch häufig von anderen Betriebssystemen gelesen werden, wäre es dumm, das Dateisystem basierend auf solchen implementierungsabhängigen Typen zu definieren. Beispielsweise kann dasselbe Dateisystem sowohl auf 32-Bit- als auch auf 64-Bit-Systemen verwendet werden und time_tdie Größe ändern. Daher müssen Dateisysteme genauer definiert werden ("32-Bit-Ganzzahl mit Vorzeichen, die die Anzahl der Sekunden seit Anfang 1970 in UTC angibt") als nur als time_t.
1
Hinweis: Der verknüpfte Wikipedia-Artikel wurde entfernt und leitet jetzt zum time.hInhaltsverzeichnis weiter. Dieser Artikel verlinkt auf cppreference.com, aber der zitierte Inhalt ist nirgends zu finden ...
Michał Górny
3
@ MichałGórny: Behoben, solange Artikel nicht gelöscht werden, können Sie immer einen Blick in den Verlauf werfen, um die richtige Version zu finden.
Zeta
4
-1; Die von Wikipedia zitierte Behauptung, dass POSIX die time_tSignatur garantiert, ist falsch. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… schreibt vor, dass verschiedene Dinge ein "vorzeichenbehafteter Integer-Typ" oder ein "vorzeichenloser Integer-Typ" sein müssen, aber time_tnur, dass es "ein Integer-Typ sein soll" . Eine Implementierung kann time_tunsigniert und dennoch POSIX-konform sein.
Ich sehe beides typedef __int32_t __time_t;und typedef __time_t time_t;in einem 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. Ihre Ergebnisse werden unter Linux explizit so festgelegt (zumindest unter 2.6.32-5-xen-amd64 von Debian).
Warum nach dem zugrunde liegenden Typ suchen __time_tund ihn nicht time_tfinden time_t? Einen Schritt weglassen?
chux
@ chux-ReinstateMonica - Das OP sagte, dass er das typedef von time_t bis __time_t gefunden habe. Diese Antwort befasst sich nur mit der Frage, wie __time_t definiert ist. Aber ich bin damit einverstanden, dass Sie für einen generischen Fall (in dem time_t möglicherweise nicht auf __time_t typisiert ist) zuerst nach time_t und dann möglicherweise erneut nach dem suchen müssen, was zurückgegeben wird
Michael Firth,
@ MichaelFirth Fair genug. Ich erinnere mich an meine Besorgnis, dass, obwohl OP festgestellt hat typedef __time_t time_t;, eine Überprüfung des umgebenden Codes erforderlich ist, um sicherzustellen, dass typedef tatsächlich verwendet wurde und nicht nur Teil einer bedingten Kompilierung ist. typedef long time_t;kann auch gefunden worden sein.
chux - Monica
30
Standards
William Brendel zitierte Wikipedia, aber ich bevorzuge es aus dem Maul des Pferdes.
Keine Notwendigkeit für die Pfeife von Echo auch:gcc -E -xc -include time.h /dev/null | grep time_t
Rvighne
12
Die Antwort ist definitiv implementierungsspezifisch. Um dies endgültig für Ihre Plattform / Ihren Compiler herauszufinden, fügen Sie diese Ausgabe einfach irgendwo in Ihren Code ein:
printf ("sizeof time_t is: %d\n",sizeof(time_t));
Wenn die Antwort 4 (32 Bit) lautet und Ihre Daten über 2038 hinausgehen sollen , haben Sie 25 Jahre Zeit, um Ihren Code zu migrieren.
Ihre Daten sind in Ordnung, wenn Sie Ihre Daten als Zeichenfolge speichern, auch wenn es so einfach ist wie:
FILE*stream =[stream file pointer that you've opened correctly];
fprintf (stream,"%d\n",(int)time_t);
Dann lesen Sie es einfach auf die gleiche Weise zurück (fread, fscanf usw. in ein int), und Sie haben Ihre Epochenversatzzeit. Eine ähnliche Problemumgehung gibt es in .Net. Ich übergebe problemlos 64-Bit-Epochennummern zwischen Win- und Linux-Systemen (über einen Kommunikationskanal). Das wirft Probleme mit der Reihenfolge der Bytes auf, aber das ist ein anderes Thema.
Um die Frage von paxdiablo zu beantworten, würde ich sagen, dass "19100" gedruckt wurde, weil das Programm so geschrieben wurde (und ich gebe zu, dass ich dies in den 80ern selbst getan habe):
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);
Die printfAnweisung gibt die feste Zeichenfolge "Year is: 19" aus, gefolgt von einer mit Nullen aufgefüllten Zeichenfolge mit den "Jahren seit 1900" (Definition von tm->tm_year). Im Jahr 2000 beträgt dieser Wert offensichtlich 100. "%02d"Pads mit zwei Nullen, werden jedoch nicht abgeschnitten, wenn sie länger als zwei Ziffern sind.
Der richtige Weg ist (nur zur letzten Zeile wechseln):
printf ("Year is: %d\n", local_date_time.tm_year +1900);
Sie sollten wahrscheinlich den %zuFormatbezeichner verwenden, um size_tWerte (wie von sizeof) zu formatieren , da sie ohne Vorzeichen ( u) sind und die Größe size_t ( z) ·
Adrian Günter haben
... oder verwenden printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));und vermeiden Sie das zProblem.
chux Stellen Sie Monica am
6
Unter Visual Studio 2008 wird standardmäßig ein verwendet, __int64sofern Sie dies nicht definieren _USE_32BIT_TIME_T. Sie tun besser so, als ob Sie nicht wissen, wie es definiert ist, da es sich von Plattform zu Plattform ändern kann (und wird).
Das funktioniert normalerweise, aber wenn Ihr Programm die Dinge verfolgen soll, die in 30 Jahren passieren werden, ist es ziemlich wichtig, dass Sie kein signiertes 32-Bit-time_t haben.
Rob Kennedy
4
@ Rob, bah, lass es! Wir werden erst 2036 anfangen, wie kopflose Hühner herumzulaufen, genau wie im Jahr 2000. Einige von uns werden eine Menge Geld damit verdienen, Berater im Jahr 2000 zu sein. Leonard Nimoy wird ein weiteres lustiges Buch darüber herausbringen, wie wir uns alle im Wald verstecken sollten ...
paxdiablo
1
... und alles wird vorbei sein, die Öffentlichkeit fragt sich, worum es in der ganzen Aufregung ging. Ich könnte sogar aus dem Ruhestand kommen, um etwas Geld für das Erbe der Kinder zu verdienen :-).
Paxdiablo
2
Übrigens, wir haben nur einen Y2K-Fehler gefunden und das war eine Webseite, auf der das Datum als 1. Januar 19100 aufgeführt war. Übung für den Leser, warum ...
paxdiablo
9
Wenn das Ereignis in 30 Jahren "Diese Sicherung ablaufen lassen" lautet, sind Sie möglicherweise JETZT in Schwierigkeiten, nicht in 2038. Fügen Sie der heutigen 32-Bit-Zeit 30 Jahre 30 Jahre hinzu, und Sie erhalten ein Datum in der Vergangenheit. Ihr Programm sucht nach zu verarbeitenden Ereignissen, findet ein überfälliges Ereignis (um 100 Jahre!) Und führt es aus. Ups, kein Backup mehr.
Rob Kennedy
5
time_tist vom Typ long intauf 64-Bit-Computern, sonst ist es long long int.
Sie können dies in diesen Header-Dateien überprüfen:
Auf den meisten älteren Plattformen handelt es sich um einen 32-Bit-Integer-Typ mit Vorzeichen. Dies führt jedoch dazu, dass Ihr Code unter dem Fehler des Jahres 2038 leidet . Moderne C-Bibliotheken sollten es daher stattdessen als signiertes 64-Bit-Int definieren, was für einige Milliarden Jahre sicher ist.
Normalerweise finden Sie diese zugrunde liegenden implementierungsspezifischen Typedefs für gcc im Verzeichnis bitsoder asmheader. Für mich ist es/usr/include/x86_64-linux-gnu/bits/types.h .
Robuster Code ist es egal, um welchen Typ es sich handelt.
C-Arten time_t, um ein echter Typ wie double, long long, int64_t, intusw. zu sein.
Es könnte sogar sein unsigned, dass die Rückgabewerte von vielen Zeitfunktionen Fehler anzeigen -1, aber nicht(time_t)(-1) - Diese Implementierungsauswahl ist ungewöhnlich.
Der Punkt ist, dass das "Bedürfnis zu wissen" des Typs selten ist. Code sollte geschrieben werden, um die Notwendigkeit zu vermeiden.
Ein häufiges "Need-to-Know" tritt jedoch auf, wenn Code das Raw drucken möchte time_t. Das Casting auf den breitesten Integer-Typ wird den meisten modernen Fällen gerecht.
time_t now =0;
time(&now);
printf("%jd",(intmax_t) now);// or
printf("%lld",(longlong) now);
Gießen eines doubleoder long doublewird auch funktionieren, doch konnte liefern ungenaue dezimal ausgegeben
Ich muss die Situation kennen, weil ich Zeit von einem ARM-System auf ein AMD64-System übertragen muss. time_t ist 32 Bit am Arm und 64 Bit am Server. Wenn ich die Zeit in ein Format übersetze und eine Zeichenfolge sende, ist dies ineffizient und langsam. Daher ist es viel besser, einfach das gesamte time_t zu senden und es auf der Serverseite zu sortieren. Allerdings muss ich den Typ ein bisschen besser verstehen, weil ich nicht möchte, dass die Zahl durch unterschiedliche Endianness zwischen den Systemen verstümmelt wird, also muss ich htonl verwenden ... aber zuerst möchte ich es wissen um den zugrunde liegenden Typ herauszufinden;)
Owl
Ein weiterer "Need to Know" -Fall, zumindest für signierte und nicht signierte, ist, ob Sie beim Subtrahieren von Zeiten vorsichtig sein müssen. Wenn Sie nur "das Ergebnis subtrahieren und drucken", erhalten Sie möglicherweise das, was Sie auf einem System mit einer vorzeichenbehafteten Zeit_t erwarten, jedoch nicht mit einer vorzeichenlosen Zeit_t.
Michael Firth
@ MichaelFirth Es gibt Fälle sowohl für die ganzzahlige vorzeichenbehaftete Zeit_t als auch für die vorzeichenlose Zeit_t, bei denen die rohe Subtraktion zu unerwarteten Ergebnissen führt. C sorgt double difftime(time_t time1, time_t time0)für einen einheitlichen Subtraktionsansatz.
chux - Monica
-3
time_tist nur typedeffür 8 Bytes ( long long/__int64), die alle Compiler und Betriebssysteme verstehen. Früher war es nur für long int(4 Bytes), jetzt aber nicht mehr. Wenn Sie sich das time_tin ansehen crtdefs.h, werden Sie beide Implementierungen finden, aber das Betriebssystem wird es verwenden long long.
alle Compiler und Betriebssysteme? Nein. Auf meinem Linux-System übernimmt der Compiler die mit 4 Bytes signierte Implementierung.
Vincent
Auf Zynq 7010-Systemen beträgt time_t 4 Byte.
Eule
1
Auf den eingebetteten Systemen, an denen ich arbeite, beträgt time_t fast immer 32 Bit oder 4 Bytes. Der Standard besagt ausdrücklich, dass es implementierungsspezifisch ist, was diese Antwort einfach falsch macht.
long int
.Antworten:
Der Artikelartikel von time_t Wikipedia beleuchtet dies. Das Fazit ist, dass der Typ
time_t
in der C-Spezifikation nicht garantiert ist.quelle
time_t
in der Datenstruktur auf der Festplatte vorkommen. Da Dateisysteme jedoch häufig von anderen Betriebssystemen gelesen werden, wäre es dumm, das Dateisystem basierend auf solchen implementierungsabhängigen Typen zu definieren. Beispielsweise kann dasselbe Dateisystem sowohl auf 32-Bit- als auch auf 64-Bit-Systemen verwendet werden undtime_t
die Größe ändern. Daher müssen Dateisysteme genauer definiert werden ("32-Bit-Ganzzahl mit Vorzeichen, die die Anzahl der Sekunden seit Anfang 1970 in UTC angibt") als nur alstime_t
.time.h
Inhaltsverzeichnis weiter. Dieser Artikel verlinkt auf cppreference.com, aber der zitierte Inhalt ist nirgends zu finden ...time_t
Signatur garantiert, ist falsch. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… schreibt vor, dass verschiedene Dinge ein "vorzeichenbehafteter Integer-Typ" oder ein "vorzeichenloser Integer-Typ" sein müssen, abertime_t
nur, dass es "ein Integer-Typ sein soll" . Eine Implementierung kanntime_t
unsigniert und dennoch POSIX-konform sein.[root]# cat time.c
[root]# gcc -E time.c | grep __time_t
typedef long int __time_t;
Es ist definiert
$INCDIR/bits/types.h
durch:quelle
typedef __int32_t __time_t;
undtypedef __time_t time_t;
in einemFreeBSD 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
. Ihre Ergebnisse werden unter Linux explizit so festgelegt (zumindest unter 2.6.32-5-xen-amd64 von Debian).__time_t
und ihn nichttime_t
findentime_t
? Einen Schritt weglassen?typedef __time_t time_t;
, eine Überprüfung des umgebenden Codes erforderlich ist, um sicherzustellen, dass typedef tatsächlich verwendet wurde und nicht nur Teil einer bedingten Kompilierung ist.typedef long time_t;
kann auch gefunden worden sein.Standards
William Brendel zitierte Wikipedia, aber ich bevorzuge es aus dem Maul des Pferdes.
C99 N1256 Standardentwurf 7.23.1 / 3 "Komponenten der Zeit" sagt:
und 6.2.5 / 18 "Typen" sagt:
POSIX 7 sys_types.h sagt:
wo
[CX]
ist definiert als :Es ist eine Erweiterung, weil es eine stärkere Garantie bietet: Gleitkommazahlen sind aus.
gcc Einzeiler
Sie müssen keine Datei erstellen, wie von Quassnoi erwähnt :
Unter Ubuntu 15.10 GCC 5.2 sind die beiden obersten Zeilen:
Befehlsaufschlüsselung mit einigen Zitaten aus
man gcc
:-E
: "Beenden Sie nach der Vorverarbeitungsphase. Führen Sie den Compiler nicht ordnungsgemäß aus."-xc
: Geben Sie die Sprache C an, da die Eingabe von stdin stammt, das keine Dateierweiterung hat.-include file
: "Datei so verarbeiten, als ob" #include "file" "als erste Zeile der primären Quelldatei angezeigt würde."-
: Eingabe von stdinquelle
gcc -E -xc -include time.h /dev/null | grep time_t
Die Antwort ist definitiv implementierungsspezifisch. Um dies endgültig für Ihre Plattform / Ihren Compiler herauszufinden, fügen Sie diese Ausgabe einfach irgendwo in Ihren Code ein:
Wenn die Antwort 4 (32 Bit) lautet und Ihre Daten über 2038 hinausgehen sollen , haben Sie 25 Jahre Zeit, um Ihren Code zu migrieren.
Ihre Daten sind in Ordnung, wenn Sie Ihre Daten als Zeichenfolge speichern, auch wenn es so einfach ist wie:
Dann lesen Sie es einfach auf die gleiche Weise zurück (fread, fscanf usw. in ein int), und Sie haben Ihre Epochenversatzzeit. Eine ähnliche Problemumgehung gibt es in .Net. Ich übergebe problemlos 64-Bit-Epochennummern zwischen Win- und Linux-Systemen (über einen Kommunikationskanal). Das wirft Probleme mit der Reihenfolge der Bytes auf, aber das ist ein anderes Thema.
Um die Frage von paxdiablo zu beantworten, würde ich sagen, dass "19100" gedruckt wurde, weil das Programm so geschrieben wurde (und ich gebe zu, dass ich dies in den 80ern selbst getan habe):
Die
printf
Anweisung gibt die feste Zeichenfolge "Year is: 19" aus, gefolgt von einer mit Nullen aufgefüllten Zeichenfolge mit den "Jahren seit 1900" (Definition vontm->tm_year
). Im Jahr 2000 beträgt dieser Wert offensichtlich 100."%02d"
Pads mit zwei Nullen, werden jedoch nicht abgeschnitten, wenn sie länger als zwei Ziffern sind.Der richtige Weg ist (nur zur letzten Zeile wechseln):
Neue Frage: Was ist der Grund für dieses Denken?
quelle
%zu
Formatbezeichner verwenden, umsize_t
Werte (wie vonsizeof
) zu formatieren , da sie ohne Vorzeichen (u
) sind und die Größe size_t (z
) ·printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
und vermeiden Sie dasz
Problem.Unter Visual Studio 2008 wird standardmäßig ein verwendet,
__int64
sofern Sie dies nicht definieren_USE_32BIT_TIME_T
. Sie tun besser so, als ob Sie nicht wissen, wie es definiert ist, da es sich von Plattform zu Plattform ändern kann (und wird).quelle
time_t
ist vom Typlong int
auf 64-Bit-Computern, sonst ist eslong long int
.Sie können dies in diesen Header-Dateien überprüfen:
time.h
:/usr/include
types.h
undtypesizes.h
:/usr/include/x86_64-linux-gnu/bits
(Die folgenden Anweisungen sind nicht nacheinander. Sie können mit Strg + F-Suche in der jeweiligen Header-Datei gefunden werden.)
1 in
time.h
2) In
types.h
3) In
typesizes.h
4) Wieder in
types.h
quelle
long int
überall. Siehe stackoverflow.com/questions/384502/…Auf den meisten älteren Plattformen handelt es sich um einen 32-Bit-Integer-Typ mit Vorzeichen. Dies führt jedoch dazu, dass Ihr Code unter dem Fehler des Jahres 2038 leidet . Moderne C-Bibliotheken sollten es daher stattdessen als signiertes 64-Bit-Int definieren, was für einige Milliarden Jahre sicher ist.
quelle
Normalerweise finden Sie diese zugrunde liegenden implementierungsspezifischen Typedefs für gcc im Verzeichnis
bits
oderasm
header. Für mich ist es/usr/include/x86_64-linux-gnu/bits/types.h
.Sie können einfach grep oder einen Präprozessoraufruf wie den von Quassnoi vorgeschlagenen verwenden, um zu sehen, welcher spezifische Header vorhanden ist.
quelle
Robuster Code ist es egal, um welchen Typ es sich handelt.
C-Arten
time_t
, um ein echter Typ wiedouble, long long, int64_t, int
usw. zu sein.Es könnte sogar sein
unsigned
, dass die Rückgabewerte von vielen Zeitfunktionen Fehler anzeigen-1
, aber nicht(time_t)(-1)
- Diese Implementierungsauswahl ist ungewöhnlich.Der Punkt ist, dass das "Bedürfnis zu wissen" des Typs selten ist. Code sollte geschrieben werden, um die Notwendigkeit zu vermeiden.
Ein häufiges "Need-to-Know" tritt jedoch auf, wenn Code das Raw drucken möchte
time_t
. Das Casting auf den breitesten Integer-Typ wird den meisten modernen Fällen gerecht.Gießen eines
double
oderlong double
wird auch funktionieren, doch konnte liefern ungenaue dezimal ausgegebenquelle
double difftime(time_t time1, time_t time0)
für einen einheitlichen Subtraktionsansatz.time_t
ist nurtypedef
für 8 Bytes (long long/__int64
), die alle Compiler und Betriebssysteme verstehen. Früher war es nur fürlong int
(4 Bytes), jetzt aber nicht mehr. Wenn Sie sich dastime_t
in ansehencrtdefs.h
, werden Sie beide Implementierungen finden, aber das Betriebssystem wird es verwendenlong long
.quelle