ฉันค้นหากล่อง Linux ของฉันและเห็น typedef นี้:
typedef __time_t time_t;
แต่ฉันไม่สามารถหา__time_t
คำจำกัดความ
ฉันค้นหากล่อง Linux ของฉันและเห็น typedef นี้:
typedef __time_t time_t;
แต่ฉันไม่สามารถหา__time_t
คำจำกัดความ
คำตอบ:
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;
อาจถูกพบเช่นกัน
มาตรฐาน
William Brendelอ้างถึง Wikipedia แต่ฉันชอบมันมากกว่าจากปากม้า
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 "file" "ปรากฏเป็นบรรทัดแรกของไฟล์ต้นฉบับ"-
: อินพุตจาก 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 ฉันผ่านหมายเลข epoch 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
ปัญหา
ภายใต้ Visual Studio 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
(คำสั่งด้านล่างไม่ใช่คำสั่งอื่น ๆ พบได้ในไฟล์ส่วนหัว resp. โดยใช้การค้นหา Ctrl + f)
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 ดังนั้นไลบรารี C ที่ทันสมัยควรกำหนดให้เป็น int 64- บิตที่มีการลงชื่อแทนซึ่งปลอดภัยสำหรับสองสามพันล้านปี
โดยทั่วไปแล้วคุณจะพบ typedef เฉพาะสำหรับการใช้งานพื้นฐานเหล่านี้สำหรับ gcc ใน bits
asm
ไดเรกทอรีหรือส่วนหัว สำหรับฉันมัน/usr/include/x86_64-linux-gnu/bits/types.h
สำหรับผมมันเป็น
คุณสามารถ grep หรือใช้การเรียกใช้ตัวประมวลผลล่วงหน้าแบบที่ Quassnoi แนะนำเพื่อดูว่าส่วนหัวใดเจาะจง
ท้ายที่สุดแล้ว time_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
คุณจะพบทั้งการใช้งาน OS long long
แต่จะใช้
long int
แล้ว