Crane
Table_bottom

Search
Loading
Table_bottom

分类
Table_bottom

随机文章
Table_bottom

标签云
Table_bottom

最新评论
Table_bottom

链接
Table_bottom

功能
Table_bottom

C语言有点变态

直接看这个程序

 

#include<stdio.h>
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输出一个负脉冲。

代码如下

library ieee;
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盘啊什么的都很方便。

软件是这个样子:

PocketWikipedia

右边那个位置本来是有图的,不知为什么没有显示出来。

可能有发烧级的觉得这个口袋版的容量太小了,不能满足要求,要知道英文wiki可是已经突破200万词条了,下面这个家伙便可以让你拥有最新wikipedia。

WikiTaxi,也是一个移动版的,不需要安装,只有两个可执行文件,一个是主程序,一个用来导入数据库,只有有了个这个数据库才能做到在本地查询,这个数据库可以到wikipedia上去下,英文数据库的地址在这里,这个是最latest的版本,bz2压缩的,大概有4.8G的大小,可以想像里面有多少内容,你也可以从朋友那里拷。有了这个后用那个包中的WikiTaxi Importer把这个xml.bz2导入成WikiTaxi database文件(以.taxi为扩展名)。PS:这个可能用的时间比较长。

有了这个.taxi文件后,执行主程序WikiTaxi,选刚才你生成的那个.taxi文件,成功的话会随机显示一个页面,然后就可以本地查询wikipedia了,速度当然一流。

WikiTaxi

可以按“CTRL+L”激活那个搜索框,而且也支持一些搜索功能,它的搜索大小写不敏感,全部按小写处理,也可以精确匹配,只需要把搜索词用双引号括起来,也可以用“- word”表示不包含某些内容,用空格分隔单词表示按and搜索,两个词中间加个OR表示匹配任意一个,是不是和google的搜索语法很像呢!See more:http://www.wikitaxi.org/

有了这些工具,我们就相当于有了一个随身携带的资料库,用知识武装到牙齿了!!

比较程序的效率

今天老师给了个这样的题:

  1. 编写程序,测试两条循环语句的执行时间。分析为何执行时间不同。
  2.  
  3. int A[ROWS][COLS];
  4. for(row=0; row<ROWS;row++)
  5.     for(col=0;col<COLS;col++)
  6.        A[row][col]=0;
  7. for(col=0;col<COLS;col++)
  8.     for(row=0; row<ROWS; row++)
  9.        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,所以程序可以这样写:

 

  1. #include<stdio.h>
  2. #include<time.h>
  3. #include<stdlib.h>
  4. #define ROWS 10000
  5. #define COLS 10000
  6. int a[ROWS][COLS];
  7. main()
  8. {
  9.         clock_t start,finish;
  10.         double elapsed1,elapsed2;
  11.         int row,col;
  12.         start=clock();
  13.         for(row=0;row<ROWS;row++)
  14.         for(col=0;col<COLS;col++)
  15.         a[row][col]=0;
  16.         finish=clock();
  17.         elapsed1=(double)(finish-start)/CLOCKS_PER_SEC;
  18.         start=clock();
  19.         for(col=0;col<COLS;col++)
  20.         for(row=0;row<ROWS;row++)
  21.         a[row][col]=0;
  22.         finish=clock();
  23.         elapsed2=(double)(finish-start)/CLOCKS_PER_SEC;
  24.         printf("the first loop cost %f seconds.\n",elapsed1);
  25.         printf("the second loop cost %f seconds.\n",elapsed2);
  26.         system("pause");
  27.         return 0;
  28. }

输出:

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嘛!

来看个程序,实战:

 

  1. #include "time.h"
  2. #include "stdio.h"
  3. int main(void)
  4. {
  5.   time_t lt;
  6.   struct tm st,*pt;
  7.   lt=time(NULL);
  8.   printf("The Calendar time now is %ld\n",lt)
  9.   lt =2147483647;
  10.   printf("The bug time(local) is %s\n",ctime(&lt));
  11.   pt=gmtime(&lt);
  12.   printf("The bug time(UTC) is %s",asctime(pt));
  13.   pt=localtime(&lt);
  14.   printf("The bug time(local) is %s\n",time(pt));
  15.   system("pause");
  16.   return 0;
  17. }

会输出:

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 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号

还是来个例子:

 

  1. #include <stdio.h>
  2. #include <time.h>
  3.  
  4. main( void )
  5. {
  6.   struct tm *newtime;
  7.   char tmpbuf[128];
  8.   time_t lt1;
  9.   time( &lt1 );
  10.   newtime=localtime(&lt1);
  11.   strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
  12.   printf(tmpbuf);
  13.   system("pause");
  14. }
  15.  

程序输出:

Today is Tuesday, day 14 of April in the year 2009.

呵呵,按我们自己的意愿了。