Risposte:
L' articolo di Time_t su Wikipedia fa luce su questo. La linea di fondo è che il tipo di time_t
non è garantito nella specifica C.
Il
time_t
tipo di dati è un tipo di dati nella libreria ISO C definito per la memorizzazione dei valori di ora del sistema. Tali valori vengono restituiti dallatime()
funzione di libreria standard . Questo tipo è un typedef definito nell'intestazione standard. ISO C definisce time_t come un tipo aritmetico, ma non specifica alcun tipo particolare , intervallo, risoluzione o codifica per esso. Inoltre non sono specificati i significati delle operazioni aritmetiche applicate ai valori temporali.I sistemi compatibili con Unix e POSIX implementano il
time_t
tipo comesigned integer
(tipicamente largo 32 o 64 bit) che rappresenta il numero di secondi dall'inizio dell'epoca Unix : mezzanotte UTC del 1 ° gennaio 1970 (senza contare i secondi bisestili). Alcuni sistemi gestiscono correttamente valori di tempo negativi, mentre altri no. I sistemi che utilizzano un tipo a 32 bittime_t
sono suscettibili al problema dell'anno 2038 .
time_t
può avvenire l' utilizzo nella struttura dei dati su disco. Tuttavia, poiché i filesystem vengono spesso letti da altri sistemi operativi, sarebbe sciocco definire il filesystem in base a tali tipi dipendenti dall'implementazione. Ad esempio, lo stesso filesystem potrebbe essere utilizzato su entrambi i sistemi a 32 e 64 bit e time_t
potrebbe cambiare dimensione. Pertanto, i filesystem devono essere definiti in modo più preciso ("numero intero con segno a 32 bit che fornisce il numero di secondi dall'inizio del 1970, in UTC") rispetto a quello time_t
.
time.h
contenuti. Quell'articolo si collega a cppreference.com ma il contenuto citato non si trova da nessuna parte ...
time_t
firma è errata. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… impone che varie cose debbano essere un "tipo intero con segno" o "tipo intero senza segno", ma time_t
ne dice semplicemente che "deve essere un tipo intero" . Un'implementazione può rendere time_t
non firmata ed essere ancora conforme a 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;
È definito $INCDIR/bits/types.h
attraverso:
# 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;
e typedef __time_t time_t;
in a 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
. I tuoi risultati sono esplicitamente impostati così in Linux (almeno su 2.6.32-5-xen-amd64 di Debian).
__time_t
e non time_t
trovare il tipo sottostante di time_t
? Omettere un passo?
typedef __time_t time_t;
, anche l'esame del codice circostante era necessario per assicurare che typedef fosse effettivamente utilizzato e non solo parte di una compilazione condizionale. typedef long time_t;
potrebbe essere stato trovato anche.
Standards
William Brendel ha citato Wikipedia, ma lo preferisco dalla bocca del cavallo.
Bozza standard C99 N1256 7.23.1 / 3 "Componenti del tempo" dice:
I tipi dichiarati sono size_t (descritti in 7.17) clock_t e time_t che sono tipi aritmetici in grado di rappresentare i tempi
e 6.2.5 / 18 "Tipi" dice:
I tipi interi e mobili sono chiamati collettivamente tipi aritmetici.
POSIX 7 sys_types.h dice:
[CX] time_t deve essere un tipo intero.
dove [CX]
è definito come :
[CX] Estensione allo standard ISO C.
È un'estensione perché fornisce una garanzia più forte: i punti mobili sono fuori.
gcc one-liner
Non è necessario creare un file come indicato da Quassnoi :
echo | gcc -E -xc -include 'time.h' - | grep time_t
Su Ubuntu 15.10 GCC 5.2 le prime due linee sono:
typedef long int __time_t;
typedef __time_t time_t;
Ripartizione dei comandi con alcune citazioni da man gcc
:
-E
: "Stop dopo la fase di preelaborazione; non eseguire correttamente il compilatore."-xc
: Specifica il linguaggio C, poiché l'input proviene da stdin che non ha estensione file.-include file
: "File di processo come se" #include "file" "apparisse come prima riga del file di origine principale."-
: input da stdingcc -E -xc -include time.h /dev/null | grep time_t
La risposta è sicuramente specifica per l'implementazione. Per scoprirlo definitivamente per la tua piattaforma / compilatore, aggiungi questo output da qualche parte nel tuo codice:
printf ("sizeof time_t is: %d\n", sizeof(time_t));
Se la risposta è 4 (32 bit) e i tuoi dati dovrebbero andare oltre il 2038 , hai 25 anni per migrare il tuo codice.
I tuoi dati andranno bene se li memorizzi come una stringa, anche se è qualcosa di semplice come:
FILE *stream = [stream file pointer that you've opened correctly];
fprintf (stream, "%d\n", (int)time_t);
Quindi rileggilo nello stesso modo (fread, fscanf, ecc. In un int) e avrai il tuo tempo di offset dell'epoca. Una soluzione simile esiste in .Net. Passo i numeri di epoca a 64 bit tra i sistemi Win e Linux senza alcun problema (su un canale di comunicazione). Ciò solleva problemi di ordinamento dei byte, ma questo è un altro argomento.
Per rispondere alla domanda di paxdiablo, direi che ha stampato "19100" perché il programma è stato scritto in questo modo (e ammetto di averlo fatto da solo negli anni '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);
L' printf
istruzione stampa la stringa fissa "L'anno è: 19" seguita da una stringa con spaziatura zero con gli "anni dal 1900" (definizione di tm->tm_year
). Nel 2000, quel valore è 100, ovviamente. "%02d"
pad con due zeri ma non si tronca se più di due cifre.
Il modo corretto è (cambia solo all'ultima riga):
printf ("Year is: %d\n", local_date_time.tm_year + 1900);
Nuova domanda: qual è la logica di questo pensiero?
%zu
identificatore di formato per formattare i size_t
valori (come resi da sizeof
), poiché sono unsigned ( u
) e di lunghezza size_t ( z
) ·
printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
ed evita il z
problema.
In Visual Studio 2008, per impostazione predefinita è un a __int64
meno che non venga definito _USE_32BIT_TIME_T
. Stai meglio solo fingendo di non sapere come è definito, dal momento che può (e cambierà) da una piattaforma all'altra.
time_t
è di tipo long int
su macchine a 64 bit, altrimenti lo è long long int
.
Puoi verificarlo in questi file di intestazione:
time.h
: /usr/include
types.h
e typesizes.h
:/usr/include/x86_64-linux-gnu/bits
(Le seguenti istruzioni non sono una dopo l'altra. Potrebbero essere trovate nel rispettivo file di intestazione usando Ctrl + f search.)
1) In time.h
typedef __time_t time_t;
2) In types.h
# define __STD_TYPE typedef
__STD_TYPE __TIME_T_TYPE __time_t;
3) In 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) Ancora una volta 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
dappertutto. Vedi stackoverflow.com/questions/384502/…
È un tipo intero con segno a 32 bit sulla maggior parte delle piattaforme legacy. Tuttavia, ciò causa al tuo codice il bug dell'anno 2038 . Quindi le librerie C moderne dovrebbero definirlo invece un int a 64 bit con segno, che è sicuro per alcuni miliardi di anni.
In genere troverai questi typedef specifici per l'implementazione sottostanti per gcc nella directory dell'intestazione bits
o asm
. Per me lo è /usr/include/x86_64-linux-gnu/bits/types.h
.
Puoi semplicemente grep o utilizzare una chiamata al preprocessore come quella suggerita da Quassnoi per vedere quale intestazione specifica.
In cosa consiste in definitiva un typedef time_t?
Il codice robusto non importa quale sia il tipo.
Le specie C time_t
devono essere un tipo reale come double, long long, int64_t, int
, ecc.
Potrebbe anche essere unsigned
che i valori restituiti da molte funzioni temporali indicano che l'errore non lo è -1
, ma (time_t)(-1)
- Questa scelta di implementazione non è comune.
Il punto è che il "bisogno di sapere" il tipo è raro. Il codice deve essere scritto per evitare la necessità.
Tuttavia si verifica un "bisogno di sapere" comune quando il codice vuole stampare il raw time_t
. La trasmissione al tipo intero più largo si adatta alla maggior parte dei casi moderni.
time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or
printf("%lld", (long long) now);
Anche il cast su un double
o long double
funzionerà, ma potrebbe fornire un risultato decimale inesatto
printf("%.16e", (double) now);
double difftime(time_t time1, time_t time0)
un approccio di sottrazione uniforme.
time_t
è solo typedef
per 8 byte ( long long/__int64
) che tutti i compilatori e i sistemi operativi comprendono. Ai tempi, era solo per long int
(4 byte) ma non ora. Se guardi time_t
dentro crtdefs.h
troverai entrambe le implementazioni ma il sistema operativo userà long long
.
long int
.