大名鼎鼎的 gnuplot 就不多介绍了。
通常我们利用数据文件绘图时,XY坐标的值都是实数,也就是我们要绘制图形的函数是R到R的映射。可有时横轴或纵轴的数据是时间值,时间的格式每次可能还都不太一样。这时我们就需要特殊设置一下 gnuplot了。
假设我们有数据文件“timedat.dat”,文件的内容如下。
#日/月/年 值 01/06/93 100 17/08/93 900 04/10/93 1300 11/10/93 300 28/10/93 1000
可以看到,横坐标是时间值,需要将这个信息告诉gnuplot。利用如下的命令。
set xdata time
类似的命令还包括:
set ydata time set zdata time set x2data time set y2data time set cbdata time
如果要回到原来的那种横坐标为数值的状态,可以执行如下命令:
set xdata
下面还需要告诉 gnuplot 数据文件中的时间格式是什么样,要利用如下的命令
set timefmt "<format string>"
其中format string 用来描述数据文件中时间的格式。对于我们的数据文件,可以这样设置:
set timefmt "%d/%m/%y"
Gnuplot 支持的格式如下:
格式
解释
%d
day of the month, 1–31
%m
month of the year, 1–12
%y
year, 0–99
%Y
year, 4-digit
%j
day of the year, 1–365
%H
hour, 0–24
%M
minute, 0–60
%s
seconds since the Unix epoch (1970-01-01 00:00 UTC)
%S
second, integer 0–60 on output, (double) on input
%b
three-character abbreviation of the name of the month
%B
name of the month
到这里就设置好了,下面开始显示
plot 'timedat.dat' using 1:2 with points ps 3 pt 6 title ""
输出的图形如下。
可以看到输出的横坐标只有月份和日期,没有年份信息。如果需要加入年份信息,可以这样设置:
set format x "%y/%m/%d"
然后更新一下输出:
Replot
这时的输出结果就满足我们的需求了。如果需要更细致的设置,请参考 gnuplot 的帮助文件。
现在遇到了一个问题:时间显示不正确。最开始是参考Gentoo的官方文档来进行设置。
ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
然后修改/etc/conf.d/hwclock中的clock="local"
但是出来的时间还是不对。
给hwclock增加参数运行
hwclock --show --debug
发现打不开/dev/rtc设备,原来配置内核时,没有把RTC的设置选中,知道问题了,重新配置内核,经过漫长的编译过程,重启,时间终于对了。
- C语言可变参简介
int printf( const char* format, ...);
它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:
printf("%d",i);
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);
- 写一个简单的可变参数的C函数
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
va在这里是variable-argument(可变参数)的意思.这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件.下面我们写一个简单的可变参数的函数,改函数至少有一个整数参数,第二个参数也是整数,是可选的.函数只是打印这两个参数的值.
void simple_va_fun(int i, ...)
{
va_list arg_ptr;
int j=0;
va_start(arg_ptr, i);
j=va_arg(arg_ptr, int);
va_end(arg_ptr);
printf("%d %d\n", i, j);
return;
}
我们在程序中可以这样调用:
从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:
1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针.
2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数.
3)然后用va_arg返回可变的参数,并赋值给整数j. va_arg的第二个参数是你要返回的参数的类型,这里是int型.
4)最后用va_end宏结束可变参数的获取.然后你就可以在函数里使用第二个参数了.如果函数有多个可变参数的,依次调用va_arg获取各个参数.
如果我们用下面三种方法调用的话,都是合法的,但结果却不一样:
1)
simple_va_fun(100);
结果是:100 -123456789(会变的值)
2)结果是:100 200
3)
结果是:100 200
- 可变参数在编译器中的处理
typedef char * va_list;
#define _INTSIZEOF(n) \
((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) \
( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
定义_INTSIZEOF(n)主要是为了某些需要内存的对齐的系统.C语言的函数是从右向左压入堆栈的,图(1)是函数的参数在堆栈中的分布位置.我们看到va_list被定义成char*,有一些平台或操作系统定义为void*.再看va_start的定义,定义为&v+_INTSIZEOF(v),而&v是固定参数在堆栈的地址,所以我们运行va_start(ap, v)以后,ap指向第一个可变参数在堆栈的地址,如图:高地址|-----------------------------|
|函数返回地址 |
|-----------------------------|
|....... |
|-----------------------------|
|第n个参数(第一个可变参数) |
|-----------------------------| <--va_start后ap指向
|第n-1个参数(最后一个固定参数)|
低地址|-----------------------------| <-- &v
图(1)
j= ( *(int*)((ap += _INTSIZEOF(int))-_INTSIZEOF(int)) );
首先ap+=sizeof(int),已经指向下一个参数的地址了.然后返回ap-sizeof(int)的int*指针,这正是第一个可变参数在堆栈里的地址(图2).然后用*取得这个地址的内容(参数值)赋给j.高地址|-----------------------------|
|函数返回地址 |
|-----------------------------|
|....... |
|-----------------------------| <--va_arg后ap指向
|第n个参数(第一个可变参数) |
&n