如何正确使用 ctime() 打印不同的时间戳

how to correctly use ctime() to print different time stamps

本文关键字:打印 时间戳 何正确 ctime      更新时间:2023-10-16

我期待以下代码应该打印不同的时间戳 t1 和 t2,但结果显示 t1 和 t2 是相同的。我哪里犯了错误?

#include<iostream>
#include<ctime>
using namespace std;
int main()
{
    time_t t1 = time(NULL);
    cout << "time now " << ctime(&t1) << endl;
    time_t t2 = t1 + 10000.0;
    cout << "time now " << ctime(&t1) << endl << " time later " << ctime(&t2) <<endl;
}

结果:

time now Thu Apr 28 20:37:03 2016
time now Thu Apr 28 20:37:03 2016
 time later Thu Apr 28 20:37:03 2016

您的问题的答案可以在 ctime() 函数的手册页中找到:

返回值指向静态分配的字符串,该字符串可能 被对任何日期和时间的后续调用覆盖 功能。

ctime() 返回一个指向它使用的内部缓冲区的指针。每次调用它时,它都会返回一个指向同一缓冲区的指针:

 cout << "time now " << ctime(&t1) << endl << " time later " << ctime(&t2) <<endl;

对于这行代码,编译器生成了调用ctime()两次的代码,然后执行 << 运算符。但是在第二次调用ctime()时,它用第二次覆盖了缓冲区,所以当<<运算符格式化输出时,因为第一次调用ctime()的结果是相同的指针,并且它指向的缓冲区已被第二次调用ctime()覆盖, 您可以在同一时间打印两次。

感谢您发布最小、完整且可验证的示例。

ctime实际上返回的是什么?从 cpp 首选项:

指向以 null 结尾的静态字符串的指针,该字符串包含日期和时间的文本表示形式。该字符串可以在std::asctimestd::ctime之间共享,并且可以在每次调用任何这些函数时被覆盖。

它可能会发现,在您的编译器上,首先调用较晚的ctime(),然后调用较新的ctime(),然后两个operator<<()都被评估 - 发出相同的char*。由于未指定的顺序,您的代码具有未定义的行为。在某些编译器上,它可以像您希望的那样工作!在你的身上,它碰巧不是。

如果将两个调用分开:

cout << "time now " << ctime(&t1) << endl;
cout << " time later " << ctime(&t2) <<endl;

你肯定会并且始终如一地看到不同的价值观。

引用自 N1570 7.27.3 时间转换函数:

除了 strftime 函数之外,这些函数每个都返回一个指向两个函数之一的指针。 静态对象的类型:分解的时间结构或 char 数组。执行 返回指向这些对象类型之一的指针的任何函数都可能覆盖 从任何返回的值指向的相同类型的任何对象中的信息 先前调用其中任何一个,并且不需要函数来避免数据竞争 彼此。

这表明从ctime()返回的内容可以被另一个ctime()调用覆盖,因此您必须复制结果才能在一个没有序列点的表达式中使用结果。

试试这个:

#include<iostream>
#include<ctime>
#include<string>
using namespace std;
int main()
{
    time_t t1 = time(NULL);
    cout << "time now " << ctime(&t1) << endl;
    time_t t2 = t1 + 10000.0;
    string t1s = ctime(&t1);
    string t2s = ctime(&t2);
    cout << "time now " << t1s << endl << " time later " << t2s <<endl;
}