C语言有点变态
直接看这个程序
int f(int x)
{
printf("%d\n",x);
}
int main(void)
{
int (*pf)(int);
pf=f; //正常用法
pf(5);
(**pf)(5); //这是什么
(****************f)(5); //这个变态啊
pf=&f; //这个也没问题
pf(6);
pf=*****f; //这是干什么
pf(7);
system("pause");
return 0;
}
看着很神奇,至少有些我从来没那样写过,但是这些全部是合法的,可以编译通过。
VHDL编程之可逆计数器
数字逻辑学了一个学期,始终都是一堆的门元件和触发器接来接去,实在是搞得人有点晕乎,到了最后大规模集成电路的时候,终于不用(好像也不可能)那些方法了,话说coding the world不是没有道理的,这大规模的电路设计最后还是得软件来搞,可惜还没到CPLD/FPGA的地步,我们就搞了一个用VHDL做的4位(其实用VHDL 的话这个位数只是个数字而已)可逆计数器,觉得蛮有意思,代码丢在这里,万一以后想到查呢?
题目是这样的:
设计一个能清0,置数和进位输出的增1/减1的4位二进制计数器。
输入信号clr为清0端,低电平有效,信号ld为置数端,也是低电平有效,将A,B,C,D的输入值送到计数器中,并立即在Qa,Qb,Qc,Qd中输出。输入信号m为模式选择端,m=1时为加1计数,m=0时为减1计数。当cp端输入一个上升沿信号时进行一次计数,有进位/借位时qcc输出一个负脉冲。
代码如下
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity counte is
port(cp,clr,ld,m:in std_logic;
abcd:in std_logic_vector(3 downto 0);
qcc:out std_logic;
qcount:out std_logic_vector(3 downto 0));
end;
architecture count of counte is
begin
process(cp,clr,ld)
begin
if(clr='0')then
qcount<="0000";
if(m='0')then
qcc<='0';
end if;
elsif(ld='0')then
if(abcd="0000" and m='0')then
qcount<=abcd;
qcc<='0';
elsif(abcd="1111" and m='1')then
qcount<=abcd;
qcc<='0';
else
qcount<=abcd;
qcc<='1';
end if;
elsif(cp'event and cp='1')then
if(qcount="1110" and m='1')then
qcount<="1111";
qcc<='0';
elsif(m='1')then
qcount<=qcount+1;
qcc<='1';
end if;
if(qcount="0001" and m='0')then
qcount<="0000";
qcc<='0';
elsif(m='0')then
qcount<=qcount-1;
qcc<='1';
end if;
end if;
end process;
end count;
其中字母基本上和上面要求对应,就是上边的qcount对应Qa,Qb,Qc,Qd。
感觉这样的begin和end的配对,而且整个程序看起来和PASCAL还是有点像的。
WikiTaxi--随身带的wikipedia
喜欢读书的朋友都可能会有过这样的想法,要是自己家有个图书馆就好了,可以天天在家看书,想看什么就看什么,不用跑图书馆了。
想必常上网的朋友也有这样的想法,wikipedia可真是个好东西,要是能搞一个在自己电脑上,那查起来不仅速度超快,而且离线也可以使用,多好啊!
其实,对于图书馆,我们没有办法,但是对于wikipedia,我们可是有不止一种办法噢!
首先是个精简版的wikipedia叫Pocket Wikipedia,这个口袋维基是一个精选版本,选出了重要的条目,而且是原汁原味的wikipedia,据说图片什么的都不少,但我查了一个Emacs没图,这个软件所有的东西都打包在一个zip包中,不到200MB,可以随身带,放U盘啊什么的都很方便。
软件是这个样子:
右边那个位置本来是有图的,不知为什么没有显示出来。
可能有发烧级的觉得这个口袋版的容量太小了,不能满足要求,要知道英文wiki可是已经突破200万词条了,下面这个家伙便可以让你拥有最新wikipedia。
WikiTaxi,也是一个移动版的,不需要安装,只有两个可执行文件,一个是主程序,一个用来导入数据库,只有有了个这个数据库才能做到在本地查询,这个数据库可以到wikipedia上去下,英文数据库的地址在这里,这个是最latest的版本,bz2压缩的,大概有4.8G的大小,可以想像里面有多少内容,你也可以从朋友那里拷。有了这个后用那个包中的WikiTaxi Importer把这个xml.bz2导入成WikiTaxi database文件(以.taxi为扩展名)。PS:这个可能用的时间比较长。
有了这个.taxi文件后,执行主程序WikiTaxi,选刚才你生成的那个.taxi文件,成功的话会随机显示一个页面,然后就可以本地查询wikipedia了,速度当然一流。
可以按“CTRL+L”激活那个搜索框,而且也支持一些搜索功能,它的搜索大小写不敏感,全部按小写处理,也可以精确匹配,只需要把搜索词用双引号括起来,也可以用“- word”表示不包含某些内容,用空格分隔单词表示按and搜索,两个词中间加个OR表示匹配任意一个,是不是和google的搜索语法很像呢!See more:http://www.wikitaxi.org/
有了这些工具,我们就相当于有了一个随身携带的资料库,用知识武装到牙齿了!!
比较程序的效率
今天老师给了个这样的题:
编写程序,测试两条循环语句的执行时间。分析为何执行时间不同。 int A[ROWS][COLS]; for(row=0; row<ROWS;row++) for(col=0;col<COLS;col++) A[row][col]=0; for(col=0;col<COLS;col++) for(row=0; row<ROWS; row++) A[row][col]=0;
于是就需要在程序中计算某一段执行的时间,找了一下,发现C/C++中的计时函数是clock(),而与其相关的数据类型是clock_t。查得clock函数定义如下:
clock_t clock( void );
这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数。其中clock_t是用来保存时间的数据类型,在time.h文件中,我们可以找到对 它的定义:
#ifndef _CLOCK_T_DEFINED
typedef long clock_t;
#define _CLOCK_T_DEFINED
#endif
很明显,clock_t是一个长整形数。在time.h文件中,还定义了一个常量CLOCKS_PER_SEC,它用来表示一秒钟会有多少个时钟计时单元,其定义如下:
#define CLOCKS_PER_SEC ((clock_t)1000)
所以我们需要使用clock()算出程序执行期间的tick总数,再除以这个CLOCKS_PER_SEC,所以程序可以这样写:
-
#include<stdio.h>
-
#include<time.h>
-
#include<stdlib.h>
-
#define ROWS 10000
-
#define COLS 10000
-
int a[ROWS][COLS];
-
main()
-
{
-
clock_t start,finish;
-
double elapsed1,elapsed2;
-
int row,col;
-
start=clock();
-
for(row=0;row<ROWS;row++)
-
for(col=0;col<COLS;col++)
-
a[row][col]=0;
-
finish=clock();
-
elapsed1=(double)(finish-start)/CLOCKS_PER_SEC;
-
start=clock();
-
for(col=0;col<COLS;col++)
-
for(row=0;row<ROWS;row++)
-
a[row][col]=0;
-
finish=clock();
-
elapsed2=(double)(finish-start)/CLOCKS_PER_SEC;
-
system("pause");
-
return 0;
-
}
输出:
the first loop cost 1.381000 seconds.
the second loop cost 6.880000 seconds.
这样哪个循环运行更快,一下子就看出来。
C/C++中的日期和时间
以前看过一个笑话,有人问一geek:Can you tell me the time now?被这样回答:Of course,it's 1229883309 seconds since 1970/1/1。
笑话归笑话,但是程序员往往能从中看出点有趣的东西出来,比如说这样的时间怎么得到,怎么用程序得到?如何将这样的时间还原成看得懂的时间?这样的计时方法有没有什么优点或者不足的地方?
其实这样的时间有个名字叫日历时间(Calendar time),要得到这样的时间很容易,C标准库就有函数可以做到,在time.h中定义了一个这样的函数:
time_t time(time_t * timer);
其中的time_t是这样定义的:
#ifndef _TIME_T_DEFINED
typedef long time_t; /* 时间值 */
#define _TIME_T_DEFINED /* 避免重复定义 time_t */
#endif
于是通过这样的函数调用 time(NULL) 就可以得到我们需要的东西,从上面的定义中可以看到,这个值是保存在一个长整型数中的,但是我们都知道长整数是有限制的,当这个数达到这个限制的时候会发生什么事呢?这可以算是Unix/Linux系统的千年虫问题了,现在一般都是32位系统,我们知道这个最大的数是2147483647,那么这会在什么时候发生呢,其实不用太担心,在2038年才会出现,准确的说是2038年1月19日03时14分07秒,不过在这么长的时间内,硬件的发展肯定可以补上这个漏洞,所以我们大可不必担心。
下来又有一个问题,如果我们得到了一个日历时间,怎么知道真实的时间呢?
同样的在time.h中有相应的函数:
char * ctime(const time_t *timer);
这个函数可以把日历时间格式化输出,像这样的样子
Tue Jan 19 11:14:07 2038
这就是上面说到的那个时间,有8小时的时差,是因为中国和UTC时间差了8个小时的原因。
其实在C标准中还有一个表示日期和时间的数据结构:
#ifndef _TM_DEFINED
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()为负。*/
};
#define _TM_DEFINED
#endif
time.h还提供了两种不同的函数将日历时间(一个用time_t表示的整数)转换为我们平时看到的把年月日时分秒分开显示的时间格式tm:
struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);
还有个函数像上面说到的ctime一样,格式输出tm结构中的日期和时间。
char * asctime(const struct tm * timeptr);
看名字就知道了,asctime嘛!
来看个程序,实战:
-
#include "time.h"
-
#include "stdio.h"
-
int main(void)
-
{
-
time_t lt;
-
struct tm st,*pt;
-
lt=time(NULL);
-
lt =2147483647;
-
pt=gmtime(<);
-
pt=localtime(<);
-
system("pause");
-
return 0;
-
}
会输出:
The Calendar time now is 1239709783
The bug time(local) is Tue Jan 19 11:14:07 2038
The bug time(UTC) is Tue Jan 19 03:14:07 2038
The bug time(local) is Tue Jan 19 11:14:07 2038
不过,如果我们不喜欢像Tue Jan 19 11:14:07 2038的形式,想按我们自己的想法输出,该怎么办呢,time.h还有个函数strftime,观名知义,格式化时间,原型如下:
size_t strftime(
char *strDest,
size_t maxsize,
const char *format,
const struct tm *timeptr
);
我们可以根据format指向字符串中格式命令把timeptr中保存的时间信息放在strDest指向的字符串中,最多向strDest中存放maxsize个字符。该函数返回向strDest指向的字符串中放置的字符数。
函数strftime()的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。格式化命令说明 串strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大小写的。
%a 星期几的简写
%A 星期几的全称
%b 月分的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年分,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日做为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十进制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号
还是来个例子:
-
#include <stdio.h>
-
#include <time.h>
-
-
main( void )
-
{
-
struct tm *newtime;
-
char tmpbuf[128];
-
time_t lt1;
-
time( <1 );
-
newtime=localtime(<1);
-
strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
-
system("pause");
-
}
-
程序输出:
Today is Tuesday, day 14 of April in the year 2009.
呵呵,按我们自己的意愿了。