C语言中的毫秒时间

69
使用以下代码:
#include<stdio.h>
#include<time.h>
int main()
{
    clock_t start, stop;
    int i;
    start = clock();
    for(i=0; i<2000;i++)
    {
        printf("%d", (i*1)+(1^4));
    }
    printf("\n\n");
    stop = clock();

    //(double)(stop - start) / CLOCKS_PER_SEC

    printf("%6.3f", start);
    printf("\n\n%6.3f", stop);
    return 0;
}

我得到以下输出:

2.169

开始和结束时间是相同的。这是否意味着程序执行所需的时间很短?

  • 如果1不成立,则至少小数点后的数字应该不同,但这里并没有发生。我的逻辑正确吗?

  • 注意: 我需要计算执行所需的时间,因此需要上述代码。


    1
    C11允许使用timespec_get函数获得纳秒级分辨率:https://dev59.com/jHRC5IYBdhLWcg3wP-n5#36095407 - Ciro Santilli OurBigBook.com
    1
    它也可能是操作系统和计算机特定的。在Linux中阅读time(7)。在Windows中,据传clock()存在缺陷(测量实时而非CPU时间)。 - Basile Starynkevitch
    8个回答

    112

    是的,这个程序可能只用了不到一毫秒的时间。尝试使用 timeval 以微秒为分辨率。

    例如:

    #include <sys/time.h>
    
    struct timeval stop, start;
    gettimeofday(&start, NULL);
    //do stuff
    gettimeofday(&stop, NULL);
    printf("took %lu us\n", (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec); 
    
    你可以查询 stop.tv_usec - start.tv_usec ��间的差异(以微秒为单位)。注意,这仅适用于亚秒时间(因为 tv_usec 会循环)。对于一般情况,请使用 tv_sectv_usec 的组合。

    编辑2016-08-19

    在支持 clock_gettime 的系统上,更合适的方法是:

    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC_RAW, &start);
    //do stuff
    clock_gettime(CLOCK_MONOTONIC_RAW, &end);
    
    uint64_t delta_us = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
    

    2
    不要忘记使用 struct timeval 而不是 timeval;前者是 @cmh 可能想要说的,而后者会导致编译错误。 - fouric
    @InkBlend:当然,你是正确的。我太习惯在C++中编写代码了,在这种情况下可以安全地省略struct - cmh
    1
    每秒钟,tv_usec将在零点回绕。表达式“stop.tv_usec - start.tv_usec”无法工作,因为事先不知道每个样本在一秒钟内的哪个时间点获得。即使是亚秒级别的时间,您也需要使用tv_sec和tv_usec。 - Adrian Lopez
    4
    请注意,直到2016年9月发布的macOS Sierra 10.12版本之前,Mac电脑上没有clock_gettime()函数(Mac OS X 10.11 El Capitan及更早版本从未有过)。在Sierra之前,除非使用Mac(Objective C)框架中隐藏的专门函数,否则gettimeofday()是该平台上最好的选择。 - Jonathan Leffler
    1
    @Elliott,这并不是绝对错误的,有一些更好的方法可以在某些系统上实现相同的目标 - 但在任何clock_gettime不可用的地方仍然有效。 - cmh
    显示剩余5条评论

    17

    这是我编写的代码,用于获取以毫秒为单位的时间戳。

    #include<sys/time.h>
    
    long long timeInMilliseconds(void) {
        struct timeval tv;
    
        gettimeofday(&tv,NULL);
        return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
    }
    

    2
    终于有一个简单的解决方案可以返回毫秒了,非常感谢!对我来说非常有效。 - anaotha

    12

    这段代码片段可以用来显示秒、毫秒和微秒:

    #include <sys/time.h>
    
    struct timeval start, stop;
    double secs = 0;
    
    gettimeofday(&start, NULL);
    
    // Do stuff  here
    
    gettimeofday(&stop, NULL);
    secs = (double)(stop.tv_usec - start.tv_usec) / 1000000 + (double)(stop.tv_sec - start.tv_sec);
    printf("time taken %f\n",secs);
    

    12

    有几件事情可能会影响您看到的结果:

    1. 您将 clock_t 视为浮点类型,但我认为它不是。
    2. 您可能期望 (1^4) 做的不是计算 1 和 4 的按位 XOR,即结果为 5。
    3. 由于 XOR 是常量之间的运算,它很可能被编译器 折叠起来, 这意味着它在运行时不会增加太多工作量。
    4. 由于输出已经被缓冲(只是格式化字符串并将其写入内存),因此它非常快速地完成。

    您没有说明您的机器速度有多快,但在现代硬件上,这很快就能运行完毕。

    如果您有,请尝试在开始/停止快照之间添加一个调用 sleep()。请注意,sleep() 是 POSIX 的函数,而不是标准 C 的。


    好的,这只是我需要执行的一个操作。 - user980411
    但是,有时我会得到像0.295这样的起始值和0.497这样的停止值。 - user980411

    10
    你可以使用gettimeofday()和下面的timedifference_msec()函数来计算两个样本之间经过的毫秒数:
    #include <sys/time.h>
    #include <stdio.h>
    
    float timedifference_msec(struct timeval t0, struct timeval t1)
    {
        return (t1.tv_sec - t0.tv_sec) * 1000.0f + (t1.tv_usec - t0.tv_usec) / 1000.0f;
    }
    
    int main(void)
    {
       struct timeval t0;
       struct timeval t1;
       float elapsed;
    
       gettimeofday(&t0, 0);
       /* ... YOUR CODE HERE ... */
       gettimeofday(&t1, 0);
    
       elapsed = timedifference_msec(t0, t1);
    
       printf("Code executed in %f milliseconds.\n", elapsed);
    
       return 0;
    }
    

    注意,当使用gettimeofday()时,即使您只关心微秒差异,也需要考虑秒数,因为tv_usec每秒都会回卷到零,并且您事先无法知道每个样本在一秒钟内获取的时间点。


    只是一个提示:"POSIX.1-2008 标记 gettimeofday() 为过时的,推荐使用 clock_gettime(2) 代替。" - 来自 "man gettimeofday()" - Roman Pietrzak

    3

    man clock得知:

    clock()函数返回程序使用的大致处理器时间。

    因此,没有迹象表明你应该将其视为毫秒。一些标准需要精确的CLOCKS_PER_SEC值,因此您可以依靠它,但我认为这是不可取的。 另一件事是,正如@unwind所述,它不是浮点/双精度。 Man times建议将其作为int类型。 还要注意以下内容:

    此函数每隔约72分钟将返回相同的值

    如果你不幸地遇到计数器刚好从零开始计数的时刻,那么就可能会得到负数或巨大的值(这取决于您将结果存储为有符号或无符号值)。

    因此:

    printf("\n\n%6.3f", stop);
    

    很可能会输出垃圾值,因为将任何整数作为浮点数处理确实是未定义的行为(我认为这可能是你遇到问题的主要原因)。如果您想确保结果准确,可以始终执行以下操作:

    printf("\n\n%6.3f", (double) stop);
    

    虽然我更愿意一开始将其打印为long long int

    printf("\n\n%lldf", (long long int) stop);
    

    我也使用了你的第二个,但仍然得到相同的结果。 - user980411
    我的意思是,你提供的C++代码是否与C语言相同。 - user980411
    1
    是的,我使用C++的唯一原因是在打印时不必猜测clock_t的类型。 - elmo

    2

    标准的C库提供了timespec_get函数。如果系统支持,它可以以纳秒精度告诉时间。但是,调用它需要更多的努力,因为它涉及到一个结构体。下面是一个函数,它只是将结构体转换为简单的64位整数,这样你就可以获取毫秒级别的时间。

    #include <stdio.h>
    #include <inttypes.h>
    #include <time.h>
    
    int64_t millis()
    {
        struct timespec now;
        timespec_get(&now, TIME_UTC);
        return ((int64_t) now.tv_sec) * 1000 + ((int64_t) now.tv_nsec) / 1000000;
    }
    
    int main(void)
    {
        printf("Unix timestamp with millisecond precision: %" PRId64 "\n", millis());
    }
    

    clock不同,此函数返回Unix时间戳,因此可以正确计算在阻塞函数(例如sleep)中花费的时间。


    $ cc -std=c11 temp.c - temp.c:8:5: warning: implicit declaration of function 'timespec_get' is invalid in C99 - Nakilon

    -10

    现代处理器运行速度过快,难以记录运行时间。因此可能会返回零。在这种情况下,您开始和结束的时间太短,因此在四舍五入后两个时间相同。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接