C / C++ 中的计时函数: clock()
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:
图 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;
}