将time_t打印为long int而不进行强制转换会产生意外行为

时间:2014-01-13 10:57:50

标签: c++ c datetime

我正在尝试打印time_t而不将其作为Microsoft Visual Studio Project中的long int进行转换,并且它给了我意想不到的结果。源代码是

#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <string.h>

int main()
{
    int a=1,b=2;
    long int c=3;
    time_t myTime;
    time(&myTime);
    printf("%d_%ld_%d_%ld",a,myTime,b,c);
    printf("\n");
    getchar();
    return 0;
}

输出为1_1389610399_0_2。这在我的linux机器上运行正常。我知道time_t不应该像这样打印但是我不确定为什么?请告诉我如何调试这样的问题?

编辑:我希望输出为1_1389610399_2_3,因为time_t被视为C中的算术。

5 个答案:

答案 0 :(得分:9)

谁说time_tlong?它可以是任何算术类型。 使用时必须将其明确地转换为某些已定义的类型 printf

使用ostream,并避免此类问题。

答案 1 :(得分:8)

  

我希望输出为1_1389610399_2_3

你错了预料到这一点。不同类型具有不同的大小,当您通过varargs传递“错误”类型时,这意味着接收器无法再在预期位置找到堆栈中的所有内容。这就是当格式化代码与参数不匹配时行为未定义的原因:接收者没有读取调用者正在编写的相同类型。

您看到的0打印出您预期的位置b,是您传递时在堆栈上放置的64位long long值的最重要的32位time_t通过varargs(在此实现中)。 %ld格式代码仅占用myTime值的前4个字节,剩下的将由下一个格式化代码占用。

当它适用于linux时,那是因为time_t在该实现上是long,因此您的格式代码与您传递的类型相匹配。

有一种“通用”方式可以打印任何有符号整数,即将其转换为intmax_t并使用格式代码%j。遗憾的是,您不能保证time_t是签名类型,甚至不是整数类型。所以这将是更多可移植但仍然不严格如此,因为理论上myTime 的值可能根本不在intmax_t的范围内。在C ++中,您应该使用std::cout << myTime;,因为这样可以避免您需要知道time_t的实际类型别名(只要它不是任何类型的char)。

或者,您可以使用difftime将时间强制转移到您知道如何打印的double。或者,您可以使用gmtimelocaltime来获取细分的日历时间,您知道如何使用printfstrftime打印每个组成部分。

答案 2 :(得分:2)

要以安全的方式显示其(time_t)内容,您应首先使用(例如)gmtime将其转换为struct tm,然后使用其中一个字段或使用strftime将其进一步转换为字符串。

答案 3 :(得分:1)

要使用格式字符串打印64位整数,您必须使用%I64d而不是%ld。 但是,因为time_t的类型取决于硬件的位数,所以要洁具。

答案 4 :(得分:0)

time()函数返回“从UTC时间1970年1月1日00:00开始经过的秒数”。

来源:http://en.cppreference.com/w/c/chrono/time_t

所以,你得到的价值(1389610399)非常好,因为它是:

1389610399/60(=分钟)/ 60(=小时)/ 24(=天)/ 365〜44年,这似乎很合理。

因此,例如,如果您想获得天数,则将时间值除以3600。 如果要获取日期,请参考其他函数,例如localtime()或gmtime() - 后者以UTC格式返回日期和时间。请参阅以下提供的示例: http://en.cppreference.com/w/c/chrono/gmtime

希望有所帮助! 格尔茨, 迈克尔