clock() 函数是 C 标准库 time.h
中的一个函数, time.h
标准库中定义了各种涉及日期和时间的函数, 变量类型和宏. 其中, clock() 函数可以返回自程序开始执行到当前位置为止, 处理器走过的时钟打点数(即”ticks”, 可以理解为”处理器时间”). 在 VC++6.0 中, 每过千分之一秒(即 1 毫秒)则 clock() 函数的返回值加 1. 但是, 处理器的时钟打点数并不是一个人类可以直观感知的时间概念, 时钟打点数只描绘了该处理器在处理该问题时所耗费的”处理器时间”. 为了能将获取到的时间转换成便于人类理解且具有普遍性的”时 分 秒”的计时方式, 我们需要引入一个常量, 在 VC++6.0 中, 使用常量 CLOCKS_PER_SEC
来进行转换且 CLOCKS_PER_SEC=1000
.
但是在不同的编译环境中, CLOCKS_PER_SEC
的数值可能是不同的. 在 Windows 10 中使用”Everything”这个程序在本机上搜索 stdio.h
可以看到我的这个计算机操作系统中存在”Emacs”, “CodeBlocks”和”Dev-cpp”三款编译器, 因此也就存在三套相互独立的 C 语言编译环境, 如图 1:
(下面以 Windows 10 下的 CodeBlocks 的编译环境为例, 查看在 C 语言的头文件中关于 CLOCKS_PER_SEC
的定义.)
在我的电脑上, CodeBlocks 的 C 语言头文件位于下面的位置:
C:\GreenSoftware\codeblocks-17.12mingw-nosetup\MinGW\include
在这个目录下找到 time.h
这个头文件, 可以在其中找到如下关于 CLOCKS_PER_SEC
的定义:
/* * Number of clock ticks per second. A clock tick is the unit by which * processor time is measured and is returned by 'clock'. */ #define CLOCKS_PER_SEC ((clock_t)1000) #define CLK_TCK CLOCKS_PER_SEC
由上面的头文件中的定义可以知道, 常量 CLOCKS_PER_SEC
的值被定义为 1000
, 变量类型为 clock_t
.
为了验证, 我们可以在 Windows 平台上的 CodeBlocks 中运行如下 C++ 程序:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <time.h> using namespace std; int main() { int i=10; clock_t start,finish; double Times, Times1; start=clock(); while(i--){ cout<<i<<endl; }; finish=clock(); Times=(double)(finish-start)/CLOCKS_PER_SEC; Times1=(double)(finish-start)/CLK_TCK; cout<<"start(时钟打点): "<<start<<endl; cout<<"finish(时钟打点): "<<finish<<endl; cout<<"CLOCKS_PER_SEC: "<<CLOCKS_PER_SEC<<endl; cout<<"CLK_TCK: "<<CLK_TCK<<endl; cout<<"运行时间(秒)(CLOCKS_PER_SEC): "<<Times<<endl; cout<<"运行时间(秒)(CLK_TCK): "<<Times1<<endl; return 0; }
控制台的输出结果是:
9 8 7 6 5 4 3 2 1 0 start(时钟打点): 5 finish(时钟打点): 6 CLOCKS_PER_SEC: 1000 CLK_TCK: 1000 运行时间(秒)(CLOCKS_PER_SEC): 0.001 运行时间(秒)(CLK_TCK): 0.001 Process returned 0 (0x0) execution time : 0.322 s Press any key to continue.
根据上面的输出结果也可以证明在 Windows 平台上的 CodeBlocks 编译器中常量 CLOCKS_PER_SEC
的值被定义为 1000
.
注: 在 VC++6.0 环境中,
CLK_TCK
和CLOCKS_PER_SEC
均被定义成1000
. 因此, 一般情况下, 在 Windows 环境中, 程序里使用CLK_TCK
或者CLOCKS_PER_SEC
的效果是一样的, 但是, 在 Linux 环境中只能使用CLOCKS_PER_SEC
.
Linux 下对于 CLOCKS_PER_SEC
这个常量的定义一般和 Windows 下是不同的.
Linux 下的 C 语言头文件通常都是放在 /usr/include
这个目录下.
(下面, 我将使用”Kali Linux 2019.1″进行本部分接下来的操作.)
在 /usr/include
目录下找到并打开 time.h
, 在其中可以看到如下内容:
/* This defines CLOCKS_PER_SEC, which is the number of processor clock ticks per second, and possibly a number of other constants. */ #include <bits/time.h>
在这个头文件里没有直接指明 CLOCKS_PER_SEC
的值, 而是选择包含了 bits/time.h
这个头文件. 于是, 我们在 /usr/include/x86_64-linux-gnu/bits
目录下找到 time.h
文件, 可以找到如下内容:
/* ISO/IEC 9899:1999 7.23.1: Components of time The macro `CLOCKS_PER_SEC' is an expression with type `clock_t' that is the number per second of the value returned by the `clock' function. */ /* CAE XSH, Issue 4, Version 2: <time.h> The value of CLOCKS_PER_SEC is required to be 1 million on all XSI-conformant systems. */ #define CLOCKS_PER_SEC ((__clock_t) 1000000)
由此我们知道, 在该 C 语言编译环境下, CLOCKS_PER_SEC
的值被定义成 1000000
.
同样地, 在 Linux 下运行如下程序也可以看到当前编译环境下 CLOCKS_PER_SEC
的数值是多少:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <time.h> using namespace std; int main() { int i=10; clock_t start,finish; double Times; start=clock(); while(i--){ cout<<i<<endl; }; finish=clock(); Times=(double)(finish-start)/CLOCKS_PER_SEC; cout<<"start(ticks): "<<start<<endl; cout<<"finish(ticks): "<<finish<<endl; cout<<"CLOCKS_PER_SEC: "<<CLOCKS_PER_SEC<<endl; cout<<"Total Times(s)(CLOCKS_PER_SEC): "<<Times<<endl; return 0; }
运行后, 控制台的输出结果是:
9 8 7 6 5 4 3 2 1 0 start(ticks): 1124 finish(ticks): 1169 CLOCKS_PER_SEC: 1000000 Total Times(s)(CLOCKS_PER_SEC): 4.5e-05
另外, 在 time.h
这个 C 标准库中, 还定义了四个库变量, 其中库变量 clock_t
的作用是存储处理器时间, 因此, 在声明 clock()
函数的时候需要使用 clock_t
声明函数的返回值类型.
使用 clock()
计算程序中一个函数运行耗时的模板如下:
#include <stdio.h> #include <time.h> /* 导入 clock() 函数的头文件. */ clock_t start, stop; /* 定义记录开始和结束时间的变量. clock_t 是 clock() 函数的返回变量类型. */ double duration; /* 记录函数运行时间, 单位为秒. */ int main(){ start=clock(); /* 记录自 main() 函数被执行开始到本次 clock() 被调用一共走过了多少个 ticks. */ MyFunction();//要进行计时的目标函数. stop=clock(); /* 记录自 main() 函数被执行开始到本次 clock() 被调用一共走过了多少个 ticks. */ duration=((double)(stop-start))/CLOCKS_PER_SEC; //将时钟打点数转换成人类可以直观感知的时间秒数. /* 不在测试范围内的操作写在这里, 例如输出 duration 的数值的操作等. */ return 0; }