Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RTC
time
minilibc 中 time 相关函数的疑问
发布于 2011-01-09 20:48:05 浏览:9394
订阅该版
前几天发现在 finsh 上使用 `set_date()` 和 `list_date()` 总是得不到正确的输出。 今天使用 mini2440 模拟器测试了一下。 过程是,为了方便测试,俺先修改了 `_libcpu/arm/s3c24x0/rtc.c`_ ```c static rt_uint32_t rtc_time = 0; static rt_err_t rtc_control(rt_device_t dev, rt_uint8_t cmd, void *args) { struct tm tm, *tm_ptr; time_t *time; RT_ASSERT(dev != RT_NULL); time = (time_t *)args; switch (cmd) { case RT_DEVICE_CTRL_RTC_GET_TIME: /* read device */ //rt_hw_rtc_get(&tm); //*((rt_time_t *)args) = mktime(&tm); *(rt_uint32_t *)args = rtc_time; rt_kprintf("get_time: %d ", rtc_time); break; case RT_DEVICE_CTRL_RTC_SET_TIME: //tm_ptr = localtime(time); /* write device */ //rt_hw_rtc_set(tm_ptr); rtc_time = *(rt_uint32_t *)args; rt_kprintf("set_time: %d ", rtc_time); break; } return RT_EOK; } ``` rtc_control() 成了伪函数,get_time 会得到 0 。 ```c void list_date() { time_t time, time1; rt_device_t device; device = rt_device_find("rtc"); if (device != RT_NULL) { rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); rt_kprintf("%d, %s ", time, ctime(&time)); } time1 = 0; rt_kprintf("time1 = %d -> %s ", time1, ctime(&time1)); time1 = 1; rt_kprintf("time1 = %d -> %s ", time1, ctime(&time1)); time1 = 60; rt_kprintf("time1 = %d -> %s ", time1, ctime(&time1)); time1 = 60*60*24; rt_kprintf("time1 = %d -> %s ", time1, ctime(&time1)); } ``` 在 list_date() 中加了些 test code 。 在 finsh 中敲 list_date() 便会输出测试结果。 [attach]0[/attach] 我研究了一下 time.c ,觉得 ctime() 的结果似乎是随机的。以下是 `_components/libc/minilibc/time.c_` 中的相关代码。 ```c char *asctime(const struct tm *timeptr) { static char buf[25]; return asctime_r(timeptr, buf); } char *ctime(const time_t *timep) { return asctime(localtime(timep)); } ``` ```c struct tm* localtime_r(const time_t* t, struct tm* r) { time_t tmp; struct timezone tz; gettimeofday(0, &tz); timezone = tz.tz_minuteswest * 60L; tmp = *t + timezone; return gmtime_r(&tmp, r); } struct tm* localtime(const time_t* t) { static struct tm tmp; return localtime_r(t, &tmp); } ``` ```c int gettimeofday(struct timeval *tp, void *ignore) { time_t time; rt_device_t device; device = rt_device_find("rtc"); if (device != RT_NULL) { rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); if (tp != RT_NULL) { tp->tv_sec = time; tp->tv_usec = 0; } return time; } return 0; } ``` ```c int __isleap(int year) { /* every fourth year is a leap year except for century years that are * not divisible by 400. */ /* return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); */ return (!(year % 4) && ((year % 100) || !(year % 400))); } struct tm *gmtime_r(const time_t *timep, struct tm *r) { time_t i; register time_t work = *timep % (SPD); r->tm_sec = work % 60; work /= 60; r->tm_min = work % 60; r->tm_hour = work / 60; work = *timep / (SPD); r->tm_wday = (4 + work) % 7; for (i = 1970;; ++i) { register time_t k = __isleap(i) ? 366 : 365; if (work >= k) work -= k; else break; } r->tm_year = i - 1900; r->tm_yday = work; r->tm_mday = 1; if (__isleap(i) && (work > 58)) { if (work == 59) r->tm_mday = 2; /* 29.2. */ work -= 1; } for (i = 11; i && (__spm* > work); --i) ; r->tm_mon = i; r->tm_mday += work - __spm*; return r; } ``` ctime() 中间有掉用到 `gettimeofday(0, &tz) :` `**ctime() -> localtime() -> localtime_r() -> gettimeofday() + gmtime_r()**` 调用时,第一个参数是空指针,第二个参数被 gettimeofday() 内部忽略。 那么,疑问一:在调用 localtime_r()时,tz,timezone 和 tmp 岂不是成了未定义的值?若如此,localtime_r() 最后调用 gmtime_r() 并返回的结果依然是未定义的。 疑问二: `localtime()` 和 asctime() 最终返回的是自己局部变量的指针。那么,这些指针所指的数据岂不是有被覆盖的危险?
![time_test.png](https://oss-club.rt-thread.org/uploads/2183_0b6fd23ed37e0fca70395e930f72d7ad.png)
![time.png](https://oss-club.rt-thread.org/uploads/2183_0411d978d72d495e84838a2b2e8be4c4.png)
查看更多
10
个回答
默认排序
按发布时间排序
onelife
2011-06-17
这家伙很懒,什么也没写!
俺在 minilibc 的 timegm() 函数中发现一个 bug : ```c /* After 2100 we have to substract 3 leap years for every 400 years This is not intuitive. Most mktime implementations do not support dates after 2059, anyway, so we might leave this out for it's bloat. */ if ((years -= 131) >= 0) { years /= 100; day -= (years >> 2) * 3 + 1; if ((years &= 3) == 3) years--; day -= years; } ``` 可改为: ```c /* After 2100 we have to substract 3 leap years for every 400 years This is not intuitive. Most mktime implementations do not support dates after 2059, anyway, so we might leave this out for it's bloat. */ if (years >= 131) { years -= 131; years /= 100; day -= (years >> 2) * 3 + 1; if ((years &= 3) == 3) years--; day -= years; } ``` 此 bug 导致时间计算错误。另外,在32位的系统中,一个32位的计数器只能从1970年数到2038年。请各位留意。 若干掉这个 bug ,再对 “struct timezone tz;” 进行一下初始化(共两处,如下),则在 FINSH 中敲入 - “set_time()” - “set_date()” - “list_date()” 可以得到正确的结果。 此方法使用 EFM32 分支在硬件上测试通过。 ```c struct tm* localtime_r(const time_t* t, struct tm* r) { time_t tmp; struct timezone tz = {0}; gettimeofday(0, &tz); timezone = tz.tz_minuteswest * 60L; tmp = *t + timezone; return gmtime_r(&tmp, r); } time_t mktime(register struct tm* const t) { time_t x = timegm(t); struct timezone tz = {0}; gettimeofday(0, &tz); timezone = tz.tz_minuteswest * 60L; x += timezone; return x; } ```
bernard
2011-01-10
这家伙很懒,什么也没写!
是的,模拟器上的时间输出不太对,而在真实的mini2440上则没有问题。 那几个libc函数确实会有这种问题,返回的是静态的变量(局部静态变量,函数执行完毕也不会释放相应的空间),即它是不可重入的。
onelife
2011-01-10
这家伙很懒,什么也没写!
>是的,模拟器上的时间输出不太对,而在真实的mini2440上则没有问题。 想不通的说,除非编译时使用的是编译器自带的 libc ,否则即使在实体 mini2440 板上跑,疑问一依然存在。 [s:169]
bernard
2011-01-10
这家伙很懒,什么也没写!
qemu模拟的时间有问题。 另外,0.4.0的时间获取方式更改了,不知道mini2440那边是否更改过来了。
wb_sxck
2011-05-04
这家伙很懒,什么也没写!
我今天调试webserver是也发现了同样的问题, `gettimeofday(0, &tz)` 这个函数有问题,无论是模拟器还是硬件上,应该都是错的
shaolin
2011-05-05
这家伙很懒,什么也没写!
>我今天调试webserver是也发现了同样的问题, >gettimeofday(0, &tz) 这个函数有问题,无论是模拟器还是硬件上,应该都是错的 --- 给你发的那份测试代码是否工作正常呢?
wb_sxck
2011-05-07
这家伙很懒,什么也没写!
可以工作,但是goahead只响应建立连接的请求。 在socketDoEvent函数里它只执行下面这些 ``` if (sp->currentEvents & SOCKET_READABLE) { if (sp->flags & SOCKET_LISTENING) { socketAccept(sp); sp->currentEvents = 0; return 1; } } ``` 程序不能往下走。
onelife
2011-05-14
这家伙很懒,什么也没写!
修改一下`localtime_r`函数(初始化`tz`),`time`就正常了。 不知在实体板上结果会如何。 ```c struct tm* localtime_r(const time_t* t, struct tm* r) { time_t tmp; struct timezone tz = {0}; gettimeofday(0, &tz); timezone = tz.tz_minuteswest * 60L; tmp = *t + timezone; return gmtime_r(&tmp, r); } ``` ![be4c4.png](https://club.rt-thread.org/uploads/2183_0411d978d72d495e84838a2b2e8be4c4.png)
bernard
2011-06-17
这家伙很懒,什么也没写!
更新到库上吧
撰写答案
登录
注册新账号
关注者
0
被浏览
9.4k
关于作者
onelife
这家伙很懒,什么也没写!
提问
6
回答
33
被采纳
0
关注TA
发私信
相关问题
1
RTC驱动框架几点建议
2
求助:RTT在STM32F407上使用内置的RTC设置日期需重启生效,设置时间即时生效,有遇到同样问题的吗?
3
[新人试水] LPC1768 Nano3_9 添加RTC
4
STM32 关于RTC的问题
5
stm32f4xx-HAL BSP的RTC设置不对
6
关于STM32的RTC设置年份不正确的问题
7
RTT的RTC驱动调试
8
rtc驱动中的bkp模块起不到防止时间的重新设置
9
rtc时钟跑十几个小时后,比实际时间快几秒怎么解决
10
stm32如何断电之后开发板rtc时间继续往前跑
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
a1012112796
13
个答案
1
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部