Linux系统编程一:时间和延时、gmtime和localtime函数返回相同

article/2025/10/14 14:30:30

目录

  • 1. 概述
  • 2. 延时函数
  • 3. 当前时间
    • 3.1 时间调用函数
    • 3.2 时间转换函数
  • 4. gmtime和localtime函数返回相同
  • 测试代码

1. 概述

前面的几篇文章Linux学习笔记一到七,主要是开发环境的搭建,都是一些准备工作。从本篇文章开始,将学习Linux系统编程。

目前我的理解,基于Linux开发,大体上可分为系统(应用)、驱动、内核三个方向,难度依次加大。从系统编程开始,除了个别需要操作硬件外设的部分,绝大多数如进程、线程、TCP,在PC端完全能够运行调试。环境相对简单,理解起来也更容易,先对Linux有一个基本的印象。

打算按照自己的思路进行,不面面俱到的罗列知识点,而是每篇都做一个小实验。先从最简单的开始,从最快上手做出东西的角度来学习。

2. 延时函数

在单片机编程时,使用软件延时常通过while循环来实现。而Linux系统编程则不再需要自己实现,延时函数有两个:sleep和usleep,前者是秒级,后者是微秒级。函数原型为:

#include <unistd.h>unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);

简单测试下延时效果,可以这样:

 while(i--) {sleep(2);printf("sleep 2\n");usleep(1000000);printf("usleep 1000000\n");}

可以在终端看到sleep 2和usleep 1000000交替打印:
在这里插入图片描述
但是我们并不知道时间是否准确,因此再增加系统时间的获取。

3. 当前时间

时间获取分为两步:调用和转换。

3.1 时间调用函数

通过时间调用函数time可以取得当前系统时间,其函数原型为:

#include <time.h>
time_t time(time_t *t)

得到的time_t类型时间值,实际是一个long型。它是一个机器日历时间,对于Linux来说也就是UNIX 纪元时间。
Unix time 是指从 1970 年 1 月 1 日 00:00:00 UTC 开始所经过的秒数。
根据传入参数是否为NULL,这个函数有两种使用方式:

time_t tiemp;time(&timep);
timep = time(NULL);

在上面延时函数的基础上略作修改,以查看time函数的作用:

    while(i--) {sleep(2);time(&timep);printf("sleep 2:UTC time: 0x08x\n", timep);usleep(1000000);timep = time(NULL);printf("usleep 1000000:UTC time: 0x08x\n", timep);}

运行结果如下:
在这里插入图片描述
可以看到:经过2秒延时,原本的unix时间0x60c80766增加2变为0x60c80768;再经过1000000微妙,也就是1秒延时,Unix时间又增加1变为0x60c80769。与预期完全相符。
这个unix时间一大长串数字,显然还需要转换为直观易懂的时间格式,比如我们常说的某年某月的某一天。

3.2 时间转换函数

时间转换函数有四个:

char *ctime(const time_t *timep);   //将时间转化为字符串格式。
struct tm *gmtime(const time_t *timep); //将时间转化为格林威治时间
struct tm *localtime(const time_t *clock);  //将时间转化为本地时间。
char *asctime(const struct tm *tm); //将时间转换为字符格式

其中,前三个函数是直接对3.1节获取到的时间进行处理,而后面三个函数都涉及一个tm结构体,结构体内包含了我们惯用的年月日时分秒:

struct tm{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()为负。

对3.1小节代码进行修改:

    while(i--) {sleep(2);time(&timep);printf("sleep 2--UTC time: 0x%08x\n", timep);printf("sleep 2--ctime is %s", ctime(&timep));	//字符串输出t_GTM = gmtime(&timep);t_local = localtime(&timep);printf("sleep 2--GTMtime is %s", asctime(t_GTM));	printf("sleep 2--localtime is %s", asctime(t_local));	printf("sleep 2--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出printf("sleep 2--localtime current hour is %d\n", t_local->tm_hour);	usleep(1000000);timep = time(NULL);printf("usleep 1000000--UTC time: 0x%08x\n", timep);printf("usleep 1000000--ctime is %s", ctime(&timep));	//字符串输出t_GTM = gmtime(&timep);t_local = localtime(&timep);printf("usleep 1000000--GTMtime is %s", asctime(t_GTM));	printf("usleep 1000000--localtime is %s", asctime(t_local));	printf("usleep 1000000--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出	printf("usleep 1000000--localtime current hour is %d\n", t_local->tm_hour);}

查看打印结果:
在这里插入图片描述
这里格林威治时间和本地时间一样呢?

4. gmtime和localtime函数返回相同

查了一圈,原来是因为连续调用gmtimelocal函数,导致后面的调用覆盖了前面的结果。调整下打印顺序:

		t_GTM = gmtime(&timep);printf("sleep 2--GTMtime is %s", asctime(t_GTM));	t_local = localtime(&timep);printf("sleep 2--localtime is %s", asctime(t_local));	

再次查看输出结果:
在这里插入图片描述
可以看到,调用local之前,是正常的格林威治时间。调用local之后,被覆盖为当地时间。

需要将调用之间的值复制到 gmtime 和 localtime :
返回值指向静态分配的结构,该结构可能会被随后对任何日期和时间函数的调用所覆盖。
这是常见的行为,至少在Linux上是如此。
(为什么localtime()和gmtime在c中给出相同的结果?)

在链接的帖子中有人提到,可以使用memcpy,也就是连续调用之间,将返回值拷贝走。对应修改下程序:

		printf("sleep 2--ctime is %s", ctime(&timep));	//字符串输出//t_GTM = gmtime(&timep);t_GTM = (struct tm*)malloc(sizeof(struct tm));memcpy(t_GTM, gmtime(&timep), sizeof(struct tm));t_local = localtime(&timep);

只修改2S延时后的处理,1000000微妙的延时不做修改。再次看下输出:
在这里插入图片描述
这种方式确实有效,只是最后别忘了free掉动态分配的内存。

测试代码

#include "stdio.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h> 
#include <time.h>int main()
{unsigned char i = 1;time_t timep;struct tm *t_GTM = NULL;struct tm *t_local = NULL;while(i--) {sleep(2);time(&timep);printf("sleep 2--UTC time: 0x%08x\n", timep);printf("sleep 2--ctime is %s", ctime(&timep));	//字符串输出//t_GTM = gmtime(&timep);t_GTM = (struct tm*)malloc(sizeof(struct tm));memcpy(t_GTM, gmtime(&timep), sizeof(struct tm));t_local = localtime(&timep);printf("sleep 2--GTMtime is %s", asctime(t_GTM));	printf("sleep 2--localtime is %s", asctime(t_local));	printf("sleep 2--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出printf("sleep 2--localtime current hour is %d\n", t_local->tm_hour);	usleep(1000000);timep = time(NULL);printf("usleep 1000000--UTC time: 0x%08x\n", timep);printf("usleep 1000000--ctime is %s", ctime(&timep));	//字符串输出t_GTM = gmtime(&timep);t_local = localtime(&timep);printf("usleep 1000000--GTMtime is %s", asctime(t_GTM));	printf("usleep 1000000--localtime is %s", asctime(t_local));	printf("usleep 1000000--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出	printf("usleep 1000000--localtime current hour is %d\n", t_local->tm_hour);free(t_GTM);}
}

http://chatgpt.dhexx.cn/article/1Os2ysx9.shtml

相关文章

逆向 time.h 函数库 time、gmtime 函数

0x01 time 函数 函数原型&#xff1a;time_t time(time_t *t)函数功能&#xff1a;返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间&#xff0c;以秒为单位。如果 seconds 不为空&#xff0c;则返回值也存储在变量 seconds 中C\C 实现&#xff1a; #include <stdio.…

python gmtime_在Python中操作日期和时间之gmtime()方法的使用

在Python中操作日期和时间之gmtime()方法的使用 这篇文章主要介绍了在Python中操作日期和时间之gmtime()方法的使用,是Python入门学习中的基础知识,需要的朋友可以参考下 gmtime()方法转换历元到一struct_time以UTC其中dst的标志值始终为0以秒表示时间。如果不设置秒时或None&a…

gmtime与localtime的区别

目录 gmtime函数 linux环境下&#xff1a; window环境下 localtime函数 gmtime函数 gmtime转换的时间是UTL时间&#xff0c;与北京时间相差了8个小时 如果你想要得到北京时间&#xff0c;不建议你将gmtime转换后的时间直接加上八个小时 linux环境下&#xff1a; 执行结…

【C库函数】strerror函数详解

目录 strerror 函数原型 参数详解 返回值详解 函数讲解 strerror 返回错误码&#xff0c;所对应的错误信息 函数原型 char *strerror( int errnum ); 参数详解 参数errnum解析错误码信息(errno) 返回值详解 strerror函数就是返回这些错误码所对应错误信息的字符串起始地…

详解:strerror函数:将错误码转化为错误信息

对于大家在浏览网页的时候&#xff0c;或多或少的会见识过不少的错误信息&#xff1a;比如&#xff1a;最常见的就是&#xff1a;404 但是&#xff0c;使用strerror函数&#xff0c;可以将错误码转化为错误信息&#xff01;不知道偶然间看见的读者是否有兴趣进行深入研究一下&…

Strerror函数和Perror函数的介绍及使用

Strerror 通过标准错误的标号&#xff0c;获得错误的描述字符串 &#xff0c;将单纯的错误标号转为字符串描述&#xff0c;方便用户查找错误。 需要引用的头文件 #include <errno.h> #include <string.h> 用法&#xff1a;如果调用函数失败&#xff0c;会产生错误码…

strerror函数使用

。 char *strerror(int errnum); 功能&#xff1a;通过标准错误的标号&#xff0c;获得错误的描述字符串 &#xff0c;将单纯的错误标号转为字符串描述。 参数&#xff1a;errnum&#xff1a;最新的错误标号。 返回值&#xff1a;指向错误信息的指针。#include <stdio.h>…

Linux 应用编程之strerror函数

在 Linux 系统下对常见的错误做了一个编号&#xff0c;每一个编号都代表着每一种不同的错误类型&#xff0c;当函数执行发生错误的时候&#xff0c;操作系统会将这个错误所对应的编号赋值给 errno 变量&#xff0c;每一个进程&#xff08;程序&#xff09;都维护了自己的 errno…

C语言函数: 字符串函数及模拟实现strtok()、strstr()、strerror()

C语言函数&#xff1a; 字符串函数及模拟实现strtok()、strstr()、strerror() strstr()函数: 作用&#xff1a;字符串查找。在一串字符串中&#xff0c;查找另一串字符串是否存在。 形参: str2在str1中寻找。返回值是char*的指针 原理&#xff1a;如果在str1中找到了str2&…

【strerror函数的使用】

strerror函数的使用 一&#xff0c;说明二&#xff0c;具体使用场景 一&#xff0c;说明 strerror会返回错误码&#xff0c;我们可以将其翻译成所对应的错误信息&#xff1b; c语言的库函数在运行的时候&#xff0c;如果发生错误&#xff0c;就会将错误码存放在一个变量中&…

strerror 函数

收藏 75 23 strerror编辑 本词条缺少 名片图&#xff0c;补充相关内容使词条更完整&#xff0c;还能快速升级&#xff0c;赶紧来 编辑吧&#xff01; 通过标准错误的标号&#xff0c;获得错误的描述字符串 &#xff0c;将单纯的错误标号转为字符串描述&#xff0c;方便用户查找…

strerror函数介绍

认识strerror 库函数调用失败的时候会产生错误码&#xff0c;而每一个错误码对应着一条错误信息&#xff0c;strerror函数的作用就是将错误码给转化成错误信息。 在C语言中有一条全局的错误码errno&#xff0c;在程序运行过程中&#xff0c;只要库函数调用失败&#xff0c;我们…

strerror perror

strerror这个函数把错误码转化为错误信息,把错误信息的起始地址返回 X86下的代码 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> int main() { printf("%s\n", strerror(0)); printf("%s\n", strerror(1…

关于strerror

1功能 strerror用于返回错误码信息的首字符的地址。 可以这样理解&#xff0c;函数运行过程中如果失败的话&#xff0c;会返回一个错误码放在errno中&#xff0c;&#xff08;原先设计中就已经存在的&#xff09;调用strerror函数的话&#xff0c;可以打印对应的错误信息 2 …

Multipass虚拟机入门教程

目录 一、Multipass介绍 二、Multipass的安装 1. 系统版本 2. 下载地址和官网教程 3. 安装 4. 查看版本并测试是否安装成功 5. 若启动失败 三、Multipass的简单使用 1. 设置虚拟化提供方式&#xff08;忽略该步骤&#xff09; 2. 创建名为test虚拟机&#xff0c;分配…

服务器vmware新建虚拟机教程,如何创建虚拟机教程全解

这部分教程我们将学习的是如何创建虚拟机。在创建虚拟机之前&#xff0c;vSphere Client是必要的软件之一&#xff0c;它用于访问ESX主机或vCenter的图形管理用户界面。 vSphere Client安装在Windows计算机上&#xff0c;它是与虚拟基础架构进行交互的主要方法。 1.安装vSphere…

专为折腾而生!老旧电脑安装PVE虚拟机保姆教程

专为折腾而生&#xff01;老旧电脑安装PVE虚拟机保姆教程 这几天玩VMware虚拟机上瘾&#xff0c;感觉特别有意思。然而我其实并不满足于只是在这种软件层面上玩玩&#xff0c;而想挑战更高级的玩法&#xff0c;比如说玩玩可以安装在实体机上的虚拟机系统~~ 说直接点就是我想在…

虚拟机Hyper-V的安装以及使用教程

目录 前言 一、什么是虚拟机Hyper-V&#xff1f; 二、使用步骤 虚拟机的安装 前言 Hyper-V是Windows操作系统提供的虚拟机管理平台&#xff0c;所有提供Hyper-V功能的Windows操作系统都可以根据本论文的内容安装并管理虚拟机。具体来说&#xff0c;Hyper-V 提供硬件虚拟化…

VirtualBox基础使用教程

选择VirtualBox而不是VMware Workstation的原因:VirtualBox是开源软件,对于个人的Linux学习来说,既免费又够用,且相较于VMware Workstation来说更为小巧,也没有那么多的自启动服务,不会在你不使用虚拟机的时候也有那么多服务在后台运行。 下载并安装VirtualBox 注:以下…

VMWare安装Linux虚拟机详细教程

使用VMware创建Linux并配置网络 1. 创建虚拟机&#xff0c;选择自定义 2. 选择硬件兼容性 3. 选择稍后安装操作系统 4. 选择Linux系统 5. 创建虚拟机名称和位置 6. 根据需求选择处理器 8. 选择虚虚拟机内存 9. 选择虚拟机的网络类型 10. 选择I/O控制器类型 11. 选择磁盘类型 1…