【北京迅为】iTOP-4412精英版使用手册-第二十二章 时间函数专题
iTOP-4412开发板【精英版】搭载三星Exynos四核处理器,配备1GB内存,4GB固态硬盘EMMC存储,兼具快速读取与大容量,纵使海量思考也能及时处理。配备三星S5M8767电源管理。配备Android、Linux+Qt、Ubuntu操作系统,开启学习、研发的全新方式。Exynos4412开发板处理器成功应用于三星GALAXYS3,联想K860,魅族MX2等热门产品当中,并取得巨大成功。功耗控制以及强劲的性能一直为业内称道,超过5000万片的出货量,足以证明其稳定性与可用性。已成为三星官方推广的处理器之一,并承诺长期供货。
第二十二章 时间函数专题
在编程中,时间的调用会经常用到,例如:
程序员想检测机器性能,那么需要运行一段代码,提取时间。
程序员需要在 log 文件中记录一些特殊时间,例如怀疑某个驱动出现了bug,就需要写个demon来多次测试重启机器,并且测试驱动是否运转正常,这里就需要用到时间。
定时的应用,在某个事件之后,经过多长时间来进行某项操作。
……
无论在任何操作系统中编程,都需要学习时间的编程,本章详细介绍 Linux 常用的时间结构体和 API 以及提供几个常用的例程。
本节配套视频为:
“视频 13_01 时间之基本概念”
“视频 13_02 时间之时间调用”
“视频 13_03 时间之时间转换”
“视频 13_04 时间之处理器性能测试”
22.1 Linux 中时间的几个基本概念
UTC时间
世界统一时间,世界各地的时间以这个为基准 。
UNIX纪元时间
Unix time 是指从 1970 年 1 月 1 日 00:00:00 UTC 开始所经过的秒数。
在 linux 中时间日期会以这种方式存储时间,有效位是秒。例如经过了 1 分钟,这个数值会变大 60 秒。
格林尼治标准时(GMT)时间
GMT 是指太阳经过英国格林尼治的时间。在英国很 NX 的时候,以格林尼治为 0 度经线,将世界分为 24 个时区。
北京时间指的是东八区的时间,和格林尼治时间相差 8 个小时。
机器日历时间
对于 Linux 来说,机器日历时间是 UNIX 纪元时间。
22.2 时间调用
时间调用函数time
函数 time_t time(time_t *t)在头文件“#include <time.h>”中
参数 1:time_t 类型,以秒为单位,如果有参数则数据传送到 time_t *t 中。
返回值:如果参数为 NULL 会返回 time_t 类型;出现错误返回-1。
其中的时间类型 time_t,它是一个 long 类型,及其机器日历时间,在头文件 time.h 中定义。
函数代码
编写简单的 gettime.c 文件测试 gettime 函数。首先添加头文件,如下图所示。
然后 main 函数如下图所示。
如上图代码所示。使用了两种方式返回时间,一种写入参数,一种写入 NULL。
编译运行测试
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/”,使用命令“mkdir time”新建 time 文件夹,将源码gettime.c 拷贝进去,进入新建的文件夹 time,如下图所示。
使用命令“arm-none-linux-gnueabi-gcc -o gettime gettime.c -static”编译 open 文件,如下图所示,使用命令“ls”可以看到生成了 gettime 可执行文件。
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统。将编译成的可执行文件 gettime,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U 盘,运行程序如下。
如上图所示,运行两次程序,两次运行有几秒间隔,那么得到的时间就会不同。
22.3 时间转换
如上面的实验所示,类似的 0x 进制数对于人类来说太不容易知道具体含义了,需要将时间转化为群众喜闻乐见的年月日时分秒的形式。这部分内容就涉及到本节介绍的时间格式转换问题。
时间 tm 结构体
如下所示
struct tm{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
其中的成员如下:
int tm_sec; 秒 – 取值区间为[0,59]。
int tm_min; 分 - 取值区间为[0,59]。
int tm_hour; 时 - 取值区间为[0,23]。
int tm_mday;一个月中的日期 - 取值区间为[1,31]。
int tm_mon;月份(从一月开始,0 代表一月) - 取值区间为[0,11]。
int tm_year;年份,其值等于实际年份减去 1900。
int tm_wday;星期 – 取值区间为[0,6],其中0表星期天,1 代表星期一,以此类推 。
int tm_yday;从每年的1月1日开始的天数–取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推。
int tm_isdst; 夏令时标识符,实行夏令时的时候,tm_isdst 为正。不实行夏令时的进候,tm_isdst 为 0;不了解情况时,tm_isdst()为负。
如果使用 time_t 类型的时间人类是无法识别,Linux 中提供了几个时间转换函数。
函数 ctime:将时间转化为字符串格式。
char *ctime(const time_t *timep);
函数 gmtime:将时间转化为格林威治时间,以 tm 结构存储。
struct tm *gmtime(const time_t *timep);
函数 asctime:将时间转换为字符格式,注意这个函数的参数是 tm 结构的。
char *asctime(const struct tm *tm);
函数 localtime:将时间转化为本地时间。
struct tm *localtime(const time_t *clock);
需要注意的是,上面几个函数的参数和以及返回值是不同的。
函数代码
编写简单的 exchangtime.c 文件测试 exchangtime 函数。首先添加头文件,如下图所示。
然后 main 函数如下图所示。
如上图代码所示。
函数 time 用于获取当前时间。
函数 ctime 将时间转为字符串。
函数 localtime 将时间转化为本地时间。
函数 gmtime 将时间转换为格林威治时间。
函数 asctime 将时间转化为本地时间。
编译运行测试
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/time”,将源码 exchangtime.c 拷贝进去,进入新建的文件夹time,如下图所示。
使用命令“arm-none-linux-gnueabi-gcc -o exchangtime exchangtime.c -static”编译 exchangtime 文件,如下图所示,使用命令“ls”可以看到生成了 exchangtime 可执行文件。
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。将编译成的可执行文件 exchangtime,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U盘,运行程序如下。
如上图所示,打印出字符串形式的时间。
小提示
在实际中,linux 单调的时间显示方式在很多场合显然不合适。这个时候用户可以将时间提取出来,自定义输出。
例如只想输出当前的时间或者当前的日期之类的。
这个步骤很简单就不再列举例程了,只需要提取时间,做个简单的处理就可以了。
22.4 测试处理器性能
测试性能以秒为单位明显不够,提高精度则需要本节介绍的函数。本节实验稍微修改一下就可以作为拿到任何开发板之后的测试例程。
高精度时间函数
函数 gettimeofday 在头文件“<sys/time.h>”中。接着介绍精度高一点的设置时间函数和读取时间函数。
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
上面两个时间函数在头文件“#include <sys/time.h>”中。先来介绍一下参数中的两个结构体。
struct timeval {
time_t tv_sec;/* seconds */
suseconds_t tv_usec;/* microseconds */
};
struct timezone {
int tz_minuteswest;/* minutes west of Greenwich,格林威治时间的时差 */
int tz_dsttime;/* type of DST correction,时间修正的方式 */
};
如上所示,介绍一下参数。
参数 tv:用于保存获取的时间。
参数 tz:可以缺省,传入 NULL。
上面获取的时间精度达到了微妙,比 time 函数获取的时间精度要高 6 个数量级。这个精度就可以用于计算代码执行时间了。
实验代码
编写简单的 precisiontime.c 文件测试 gettimeofday 和 settimeofday 函数。首先添加头文件,如下图所示。
然后看一下耗时的函数,比较简单就是一个循环。
然后 main 函数如下图所示。
如上图代码所示。通过 gettimeofday 获取两次当前时间,运行耗时函数之后计算差值,最后将耗时计算出来。
编译运行测试
在 Ubuntu 系统下,如下图所示,进入前面实验创建的目录“/home/linuxsystemcode/time,将源码 precisiontime.c 拷贝进文件夹 time,如下图所示。
使用命令“arm-none-linux-gnueabi-gcc -o precisiontime precisiontime.c -static” 编译 precisiontime 文件,如下图所示,使用命令“ls”可以看到生成了 precisiontime 可执行文件。
这里介绍 U 盘拷贝代码的方法,也可以编译进文件系统,具体方法参考 10.3.5 小节。将编译成的可执行文件 precisiontime,拷贝到 U 盘,启动开发板,插入 U 盘,加载 U盘,运行程序如下。
如上图所示,可以看到这个循环耗时为 0.088172 秒。
22.5 man命令的使用
在开发板的使用手册中,简单的介绍过使用 man 查找 linux 的命令,但是强大的 man 命令不止查找命令这一个简单的功能。还可以查找各种 API 函数,想要学会 linux 编程,这个man 命令一定要非常熟练度的掌握。
man 命令熟悉之后,很多东西就可以不用教程,不用手册,可以自己进行学习了。将来大家独立做实际项目或者学习的时候,会经常用到 man 命令的。
在做技术支持的时候,很多同学问到如何学习英语。
我的回答很简单“看到不会的单词,记下来,有空的时候看一下,直到记住为止”。工作中用到的专业英语,没有捷径,只有一遍一遍的记,一个一个的记。
在这件事情上,对所有人都是公平公正的,一份耕耘一份收获! 不过专业词汇也没有几个,一般很快就流畅了。
大多数用户学习这里,会感到一点迷茫或者吃力。觉得那么多函数,那么多头文件,怎么记得住!
事实上,学习到一个阶段之后,就需要自学了,那么到了什么程度可以开始自学?怎么自学呢?
利用提供的教程,对 linux 的整个知识框架有较全面的了解之后,如果自己感觉对某一个知识点不了解,可以看一下网上对应的文章,这里强烈建议大家使用 Google 去学习。
另外就是看官方的手册,学习 window 或者 Android 的开发,都是学习开发文档,开发文档中提供了详细学习和编程资料。在 linux 下编程,用的最多的就是 man 命令,man 命令就类似 window 和 Android 下的开发文档,极其强大。
其实使用 man 命令可以很容易查到最权威的头文件,函数定义,函数参数,函数描述等等。
前面介绍 man 命令,只是针对 linux 命令简单的介绍了一下,本章给大家介绍如何使用man 命令查找资料,以及资料的结构。
man 系统
先来学习一下 man 系统的信息,man 命令本身也是一个阅读文档的小程序,man 也是属于 linux 命令,那么使用 man 命令是可以查询 linux 命令的,根据慢查阅的语法就可以使用“man man”查找 man 相关的文档资料(很绕口,可以看下面的例子)。
如下图所示,在 Ubuntu 系统下使用命令“man man”,来查阅一下 man 本身。
如下图所示,是 man 命令相关的资料文档。
如下图所示,man 命令文档非常多,在 Ubuntu16.04.2 上有 700 多页(注意不同的linux 系统下,因为版本不同 man 命令稍微会有点区别的,不过大概的用法都是类似)
man 的分页
通常情况下,UNIX 系统上的所有软件(包括每个命令行实用程序、每个系统调用、编程库中每个可调用的函数和每种文件格式)都包含一个手册页。实际上,在构建新软件时编写并提供手册页被认为是一种必要的 “礼节”。
在以前,手册页存储库曾经放在 /usr/man。最近,存储位置已经改为/usr/share/man,但是具体位置因 UNIX 版本而异。另外,软件包经常把它的手册页放在自己的根目录的子目录中。例如,MySQL 数据库引擎的一些版本把手册页存储在/usr/local/mysql/man 中。这些策略都是允许的,但是,如果手册页分散在许多存储库中,就需要一些额外的配置。
如下图所示,是打开 man 文档之后的截图,红色箭头指的 man 后面有个(1)。
无论它的位置在哪里,每个存储库都划分为一个或多个部分。每个部分实现为一个独立的子目录。每个部分按惯例命名为 man1、man2 直到 man8,分别包含一类命令的手册页。
表 1 列出部分名及其内容。
man 手册分页的标准内容。
man1 | 一般命令。这个部分中的命令通常不需要超级用户(即管理员)特权。 ls、cat 和 passwd 放在这里,还有 shell。例如,请试试 man bash。 |
man2 | 用来访问 UNIX 内核提供的服务的系统调用或函数。例如 fork 系统,它从一个现有的进程生成一个新进程。输入 man fork 显示它的手册页。使 用系统软件的程序员常常参考这个部分。 |
man3 | C 库函数。许多软件包提供功能丰富的代码库,让开发人员可以创建新软件来补充现有的特性或开发全新的特性。每个库通常有一个手册页;一些库(比如系统的 libc)太大了,所以各个函数或一组相关函数有单独的文档。 |
man4 | 特殊文件,比如设备和驱动程序。 |
man5 | 文件格式。UNIX 几乎完全使用文本配置文件定制系统的操作。有大量配置文件,包括网络服务的列表 (/etc/services) 和可用的 shell 列表(/etc/shells) 等等。 |
man6 | 游戏和屏幕保护程序。 |
man7 | 杂类文件。这是一个包罗万象的类别。在传统的系统上,可以了解 glob操作符、正则表达式等方面的信息。 |
man8 | 系统管理命令,超级用户很可能要使用它们。 |
上面的 8 种 man 命令,通常使用的 man1、man2 和 man3 比较多,而且并不是所有的都有上面八种文档,有的只有一种,或者两种文档。
可能前面“man man”大家还是不太容易理解。后面举几个容易理解的例子,大家稍微加把劲,很快就能熟练应用了。
手册页的框架
尽管各个命令的选项差异很大,但是手册页的内容相当有规律。实际上,手册页之所以是宝贵的参考资料,就是因为它们符合惯例。阅读一小段文字之后,您很快就能够跳到文档的正确部分,找到您要找的信息。
最简单的手册页包含五个部分:名称、大纲、描述、一些示例和其他相关资料的引用。
name(名称)给出命令、函数或文件格式的名称,以及对软件作用的单行的准确描述。
synopsis(大纲)简要描述如何使用这个软件。如果手册页的主题是命令,那么这个部分显示必需的和可选的选项、参数的格式和参数次序。如果主题是系统调用或库函数,那么这个部分显示函数的形式参数以及使用函数所需的头文件(如果有的话)。
例如,下面是 BSD UNIX 上 du 命令的大纲。
du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k | -m | -g] [-x] [-I mask] [file ...]
命令大纲中使用的表示法是手册系统中有帮助的惯例之一(一些建模实用程序提供的使用方法提示借鉴了这种表示法)。这里的大纲的意思是,“输入 du;可选地输入 -H、-L 或 - P 选项之一;然后,可选地输入 -a、-s 或 -d 之一,但是如果使用最后一个选项,还要指定一个深度(depth);指定 -c,也可以不指定;可选地输入 -h、-k、-m 或 -g 之一;指定-x,也可以不指定;指定 -I 和一个掩码,也可以不指定;最后,提供一个或多个文件名。省略号 (...) 表示多于一个。
分组在一起的选项(比如第一组 -H、-L 和 -P)的关系就像是图形用户界面 (GUI) 中的单选按钮:只能选择其中一个。独立的选项(比如 -c 和 -x)就像是复选框:可以打开或关闭。这种表示法很容易阅读,很快就可以按照它输入命令。
下面是 open() 系统调用的大纲:
#include <fcntl.h>
int open(const char *path, int oflag, ...);
这个大纲表明,需要头文件 fcntl.h,open() 返回一个整数,必须指定要打开的文件的路径和一组决定模式(只读、读/写、打开并截断等等)的标志。
description(描述)部分讨论特性、使用方法和命令行上可以使用的所有选项。如果想知道 du -H 的作用,可以阅读描述中的文本。
examples(示例)部分给出实用程序的一般用途、常见的特殊情况和解释。
最后一部分 See Also(参见)提供相关资料的引用,比如其他相关命令、重要的系统文件、行业标准规范等等。
除了前面提到的几个部分,在手册页中可能还有其他特殊部分。一个重要的部分是“Environment(环境)”。可以设置它列出的环境变量来影响实用程序的操作。例如, man 的手册页列出 10 个多环境变量,可以通过修改它们定制 man。其中之一是MANPATH,它指定寻找手册页时要搜索的目录。
Linux命令手册页举例1
下面给大家看一下 sleep 命令,如下图所示,使用命令“man sleep”,先不带页。
如上图所示,可以看到 NAME,DESCRIPTION,AUTHOR。
NAME 中描述了函数名是 sheep,以及基本功能是延时一段时间
SYNOPSIS 描述了如何使用这个程序,sleep 后面加数字 number
UTHOR 是作者,也就是谁写的这个文档。
DESCRIPTION 是描述这个程序特性、使用方法以及可以使用的选项。
如下图所示,向下翻。
如上图所示,可以看到 REPORTING BUGS、COPYRIGHT、SEE ALSO
REPORTING BUGS 如果发现使用的时候发现了 BUG,可以怎么提交报告。
COPYRIGHT 版权,版权要遵循一系列的 GPL 协议,在后面驱动教程中会介绍 GPL 协议。
SEE ALSO 参见,提供引用的相关资料。sleep(3)这个要注意,也就是说这个 sleep 在 C 库页部分,可以使用“man 3 sleep”。
使用命令“man 1 sleep”,那么查找的就是函数 sleep 的命令,本小节的是 sleep(1),
使用命令“man 3 sleep”,查找的就是 c 库中的用法了。
还会提示可以使用其它的页。
Linux 命令手册页举例 2
接着看一下“man 3 sleep”命令,如下图所示。
如下图所示。
如上图所示,有 NAME,SYNOPSIS,DESCRIPTION,RETURN VALUE, CONFORMING TO,BUGS 等
可以看到地方 sleep 只能延时秒了,前面 sleep 命令是可以延时天和小时的。这里作为 c 的库文件,介绍了头文件以及函数原型,返回值等等前面一张图下翻,如下图所示。
如上图所示,特别要注意上面的 SEE ALSO,它会介绍相关的函数,也就是在某些场合的应用有相关性的函数,这里有 alarm,nanosleep,signal,signal,因为这几个函数都可以实现延时功能,不过属于不同的方式。
另外 alarm(2),括号的 2 表示可以使用“man 2 sleep”查看它。
前面介绍的专题延时、专题时间管理以及后面要介绍的专题,大家在使用的实验手册之余,可以使用 man 命令参考着学习!
这个 man 命令易学,容易上手,虽然初期需要花习惯使用英文,但是一旦大家习惯了, 对大家后面的发展会有很大的帮助的。
这个过程非常重要,介绍的东西,只是其中的一部分。如果大家将来需要用到其它部分, 那么还是需要使用 man 命令来查找相关文档的。