Apa itu time_t akhirnya typedef?

195

Saya mencari di kotak Linux saya dan melihat typedef ini:

typedef __time_t time_t;

Tetapi saya tidak dapat menemukan __time_t definisi tersebut.

kal
sumber

Jawaban:

175

The time_t artikel Wikipedia Artikel memberi petunjuk pada ini. Intinya adalah bahwa jenis time_ttidak dijamin dalam spesifikasi C.

Tipe time_tdata adalah tipe data dalam pustaka ISO C yang didefinisikan untuk menyimpan nilai waktu sistem. Nilai-nilai tersebut dikembalikan dari time() fungsi perpustakaan standar . Tipe ini adalah typedef yang didefinisikan dalam header standar. ISO C mendefinisikan time_t sebagai tipe aritmatika, tetapi tidak menentukan tipe , rentang, resolusi, atau penyandian tertentu untuk itu. Juga tidak ditentukan adalah arti operasi aritmatika yang diterapkan pada nilai waktu.

Sistem Unix dan POSIX-compliant menerapkan time_ttipe sebagai a signed integer(biasanya lebar 32 atau 64 bit) yang mewakili jumlah detik sejak dimulainya zaman Unix : tengah malam UTC 1 Januari 1970 (tidak termasuk detik kabisat). Beberapa sistem dengan benar menangani nilai waktu negatif, sementara yang lain tidak. Sistem yang menggunakan tipe 32-bit time_trentan terhadap masalah Tahun 2038 .

William Brendel
sumber
6
Perhatikan, bagaimanapun, bahwa nilai time_t biasanya hanya disimpan dalam memori, bukan pada disk. Sebagai gantinya, time_t dikonversi ke teks atau format portabel lainnya untuk penyimpanan persisten. Itu membuat masalah Y2038 menjadi tidak terlalu masalah.
11
@Heath: pada sistem tertentu, di mana orang yang sama membuat sistem operasi dan pustaka C, menggunakan time_tdalam struktur data pada disk dapat terjadi. Namun, karena filesystem sering dibaca oleh sistem operasi lain, itu akan konyol untuk mendefinisikan filesystem berdasarkan pada jenis tergantung implementasi. Sebagai contoh, sistem file yang sama dapat digunakan pada sistem 32-bit dan 64-bit, dan time_tmungkin berubah ukuran. Dengan demikian, filesystem perlu didefinisikan secara lebih tepat ("integer bertanda 32-bit yang memberikan jumlah detik sejak awal 1970, dalam UTC") daripada hanya sebagai time_t.
1
Sebagai catatan: artikel Wikipedia yang tertaut telah dihapus, dan sekarang diarahkan ke daftar time.hkonten. Artikel itu terhubung ke cppreference.com tetapi konten yang dikutip tidak ditemukan ...
Michał Górny
3
@ MichałGórny: Diperbaiki, selama artikel tidak dihapus, Anda selalu dapat melihat riwayat untuk menemukan versi yang benar.
Zeta
4
-1; klaim yang dikutip dari Wikipedia bahwa jaminan POSIX yang time_tditandatangani tidak benar. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… menyatakan bahwa berbagai hal harus berupa "tipe integer yang ditandatangani" atau "tipe integer yang tidak ditandatangani", tetapi time_thanya dikatakan bahwa itu "akan menjadi tipe integer" . Implementasi dapat membuat time_tunsigned dan masih kompatibel dengan POSIX.
Mark Amery
112

[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;

Ini didefinisikan $INCDIR/bits/types.hmelalui:

# 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
Quassnoi
sumber
1
Saya melihat keduanya typedef __int32_t __time_t;dan typedef __time_t time_t;dalam 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. Hasil Anda secara eksplisit diatur seperti itu di Linux (setidaknya pada 2.6.32-5-xen-amd64 dari Debian).
ssice
1
@Viet juga mungkin dengan satu-kapal tanpa menciptakan file: stackoverflow.com/a/36096104/895245
Ciro Santilli郝海东冠状病六四事件法轮功
1
Mengapa mencari __time_tdan tidak time_tmenemukan jenis yang mendasarinya time_t? Menghilangkan langkah?
chux
@ chux-ReinstateMonica - OP mengatakan bahwa ia telah menemukan typedef dari time_t ke __time_t. Jawaban ini hanya menjawab pertanyaan yang diajukan tentang apakah __time_t didefinisikan sebagai. Tapi saya setuju bahwa untuk kasus generik (di mana time_t mungkin tidak diketikkan menjadi __time_t), Anda perlu grep untuk time_t pertama, dan kemudian mungkin grep lagi untuk apa yang kembali
Michael Firth
@MichaelFirth Cukup adil. Saya ingat kekhawatiran saya meskipun OP menemukan typedef __time_t time_t;, pemeriksaan kode di sekitarnya juga diperlukan untuk memastikan bahwa typedef sebenarnya digunakan dan bukan hanya bagian dari kompilasi bersyarat. typedef long time_t;mungkin telah ditemukan juga.
chux
30

Standar

William Brendel mengutip Wikipedia, tetapi saya lebih suka dari mulut kuda.

C99 N1256 draft standar 7.23.1 / 3 "Komponen waktu" mengatakan:

Tipe yang dideklarasikan adalah size_t (dijelaskan pada 7.17) clock_t dan time_t yang merupakan tipe aritmatika yang mampu merepresentasikan waktu

dan 6.2.5 / 18 "Jenis" mengatakan:

Tipe integer dan mengambang secara kolektif disebut tipe aritmatika.

POSIX 7 sys_types.h mengatakan:

[CX] time_t akan menjadi tipe integer.

mana [CX]yang didefinisikan sebagai :

[CX] Perpanjangan ke standar ISO C.

Ini adalah perpanjangan karena itu membuat jaminan yang lebih kuat: floating point keluar.

gcc one-liner

Tidak perlu membuat file seperti yang disebutkan oleh Quassnoi :

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

Pada Ubuntu 15.10 GCC 5.2 dua baris teratas adalah:

typedef long int __time_t;
typedef __time_t time_t;

Command breakdown dengan beberapa kutipan dari man gcc:

  • -E: "Berhenti setelah tahap preprocessing; jangan jalankan compiler dengan benar."
  • -xc: Tentukan bahasa C, karena input berasal dari stdin yang tidak memiliki ekstensi file.
  • -include file: "Memproses file seolah" #include "file" "muncul sebagai baris pertama dari file sumber utama."
  • -: masukan dari stdin
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
1
Tidak perlu untuk pipa dari gema juga:gcc -E -xc -include time.h /dev/null | grep time_t
rvighne
12

Jawabannya jelas khusus untuk implementasi. Untuk mengetahui secara pasti untuk platform / kompiler Anda, cukup tambahkan output ini di suatu tempat dalam kode Anda:

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

Jika jawabannya adalah 4 (32 bit) dan data Anda dimaksudkan untuk melampaui 2038 , maka Anda memiliki 25 tahun untuk memigrasi kode Anda.

Data Anda akan baik-baik saja jika Anda menyimpan data Anda sebagai string, meskipun itu sesuatu yang sederhana seperti:

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

Kemudian baca saja kembali dengan cara yang sama (fread, fscanf, dll menjadi int), dan Anda memiliki waktu offset zaman Anda. Solusi serupa ada di. Net. Saya melewati nomor zaman 64-bit antara sistem Win dan Linux tanpa masalah (melalui saluran komunikasi). Itu memunculkan masalah pemesanan byte, tapi itu topik lain.

Untuk menjawab pertanyaan paxdiablo, saya akan mengatakan bahwa itu dicetak "19100" karena program ini ditulis dengan cara ini (dan saya akui saya melakukannya sendiri di tahun 80-an):

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);

The printfpernyataan mencetak string tetap "Tahun ini: 19" diikuti dengan string nol-empuk dengan "tahun sejak tahun 1900" (definisi tm->tm_year). Pada tahun 2000, nilai itu adalah 100, jelas. "%02d"bantalan dengan dua nol tetapi tidak terpotong jika lebih dari dua digit.

Cara yang benar adalah (ubah hanya ke baris terakhir):

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

Pertanyaan baru: Apa alasan pemikiran itu?

pwrgreg007
sumber
2
Anda mungkin harus menggunakan %zupenentu format untuk memformat size_tnilai (seperti yang dihasilkan oleh sizeof), karena mereka tidak ditandatangani ( u) dan dengan panjang size_t ( z) ·
Adrian Günter
... atau gunakan printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));dan hindari zmasalah ini.
chux
6

Di bawah Visual Studio 2008, itu default ke __int64kecuali Anda mendefinisikan _USE_32BIT_TIME_T. Anda lebih baik berpura-pura tidak tahu apa itu didefinisikan, karena itu dapat (dan akan) berubah dari platform ke platform.

Gerhana
sumber
2
Itu biasanya berhasil, tetapi jika program Anda dimaksudkan untuk melacak hal-hal yang akan terjadi 30 tahun dari sekarang, cukup penting bahwa Anda tidak memiliki time_t 32-bit yang sudah ditandatangani.
Rob Kennedy
4
@Rob, bah, tinggalkan saja! Kami akan mulai berlarian seperti ayam tanpa kepala di tahun 2036, sama seperti yang kami lakukan untuk Y2K. Beberapa dari kita akan menghasilkan banyak uang dari menjadi konsultan Y2k38, Leonard Nimoy akan mengeluarkan buku lucu lain tentang bagaimana kita semua harus bersembunyi di hutan ...
paxdiablo
1
... dan semuanya akan reda, publik bertanya-tanya apa yang terjadi. Saya bahkan mungkin keluar dari masa pensiun untuk menghasilkan uang untuk warisan anak-anak :-).
paxdiablo
2
BTW, kami hanya menemukan satu bug Y2K dan itu adalah halaman web yang mencantumkan tanggal sebagai 1 Januari 19100. Latihan untuk pembaca mengapa ...
paxdiablo
9
Jika acara yang terjadi dalam 30 tahun adalah "kadaluwarsa cadangan ini," maka Anda mungkin dalam kesulitan SEKARANG, bukan pada 2038. Tambahkan 30 tahun ke time_t 32-bit hari ini, dan Anda mendapatkan tanggal di masa lalu. Program Anda mencari acara untuk diproses, menemukan acara yang sudah lewat waktu (hingga 100 tahun!), Dan menjalankannya. Ups, tidak ada lagi cadangan.
Rob Kennedy
5

time_tadalah tipe long intpada mesin 64 bit, selain itu long long int.

Anda dapat memverifikasi ini di file header ini:

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

(Pernyataan di bawah ini tidak satu demi satu. Mereka dapat ditemukan di file header resp menggunakan pencarian Ctrl + f.)

1) Dalam time.h

typedef __time_t time_t;

2) Dalam types.h

# define __STD_TYPE     typedef  
__STD_TYPE __TIME_T_TYPE __time_t;  

3) Dalam 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) Lagi di 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;
abcoep
sumber
File-file itu disediakan oleh glibc di Ubuntu 15.10 BTW.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
3
Itu tidak ada di long intmana - mana. Lihat stackoverflow.com/questions/384502/…
Zan Lynx
4

Ini adalah tipe integer bertanda 32-bit pada sebagian besar platform lawas. Namun, itu menyebabkan kode Anda menderita bug tahun 2038 . Jadi perpustakaan C modern harus mendefinisikannya sebagai int 64-bit yang ditandatangani sebagai gantinya, yang aman untuk beberapa miliar tahun.


sumber
3

Biasanya Anda akan menemukan typedef khusus implementasi yang mendasari ini untuk gcc di direktori bitsatau asmheader. Bagi saya, ini/usr/include/x86_64-linux-gnu/bits/types.h .

Anda bisa saja grep, atau menggunakan doa preprocessor seperti yang disarankan oleh Quassnoi untuk melihat header tertentu.

poolie
sumber
1

Apa yang akhirnya menjadi typ timeef?

Kode yang kuat tidak peduli apa jenisnya.

Spesies C time_tmenjadi tipe nyata seperti double, long long, int64_t, int, dll.

Bahkan bisa unsignedsebagai nilai pengembalian dari banyak fungsi waktu menunjukkan kesalahan tidak -1, tetapi(time_t)(-1) - Pilihan implementasi ini tidak umum.

Intinya adalah bahwa "perlu tahu" jenisnya jarang. Kode harus ditulis untuk menghindari kebutuhan.


Namun "perlu tahu" yang umum terjadi ketika kode ingin mencetak mentah time_t. Casting ke tipe integer terluas akan mengakomodasi sebagian besar case modern.

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

Casting ke doubleatau long doubleakan bekerja juga, namun bisa memberikan output desimal yang tidak tepat

printf("%.16e", (double) now);
chux - Pasang kembali Monica
sumber
Saya perlu tahu situasi karena saya perlu mentransfer waktu dari sistem ARM ke sistem AMD64. time_t adalah 32 bit di lengan, dan 64 bit di server. jika saya menerjemahkan waktu ke dalam format, dan mengirim string, itu tidak efisien dan lambat. Oleh karena itu jauh lebih baik untuk mengirim seluruh time_t dan mengatasinya di server. Namun, saya perlu memahami jenisnya sedikit lebih karena saya tidak ingin nomornya hancur oleh perbedaan endianness antara sistem, jadi saya perlu menggunakan htonl ... tapi pertama-tama, berdasarkan kebutuhan untuk mengetahui, saya ingin untuk mengetahui tipe yang mendasarinya;)
Owl
Kasus "perlu tahu" lainnya, setidaknya untuk yang ditandatangani vs yang tidak ditandatangani adalah apakah Anda perlu berhati-hati saat mengurangi waktu. Jika Anda hanya "kurangi dan cetak hasilnya", maka Anda mungkin akan mendapatkan apa yang Anda harapkan pada sistem dengan time_t yang ditandatangani, tetapi tidak dengan time_t yang tidak ditandatangani.
Michael Firth
@MichaelFirth Case tersedia untuk integer ditandatangani time_t dan unsigned time_t di mana pengurangan mentah akan menghasilkan hasil yang tidak terduga. C menyediakan double difftime(time_t time1, time_t time0)pendekatan pengurangan yang seragam.
chux - Reinstate Monica
-3

time_thanya typedefuntuk 8 byte ( long long/__int64) yang dimengerti oleh semua kompiler dan OS. Kembali pada hari-hari, dulu hanya untuk long int(4 byte) tetapi tidak sekarang. Jika Anda melihat di time_tdalam crtdefs.hAnda akan menemukan kedua implementasi tetapi OS akan digunakan long long.

bvrwoo_3376
sumber
5
semua kompiler dan OS? Tidak. Pada sistem linux saya, kompiler mengambil implementasi yang ditandatangani 4 byte.
Vincent
Pada sistem Zynq 7010, time_t adalah 4bytes.
Burung hantu
1
Pada sistem tertanam saya bekerja pada time_t hampir selalu 32-bit atau 4 byte. Standar ini secara khusus menyatakan bahwa implementasi spesifik yang membuat jawaban ini salah.
Cobusve