• 网志分类
  • » 查看所有日志 (102)
  • 最新评论
  • 站内搜索
  • 友情链接
  • » 我的歪酷 非非共享界
    » 梦随风万里
    » 爱睡觉的猫
    » 踏水逐浪,随风寻梦
    » 四月的时光
    » gorilla's home
    » 哈求乐园
    » Cooltree
    » xixixixi
    » tobaby

    订阅 RSS

    歪酷博客

    0042782

    小山丘 @ 2008-01-07 11:01

    字符串长度
        ${#string}
        expr length $string
        expr "$string" : '.*'
    从字符串开始的位置匹配字串的长度
        expr match "$string" '$substring'
        expr "$string" : '$substring'
            $substring 是一个正则表达式
    索引
        expr index $string $substring
    提取子串
        ${string:position}
            在string 中从位置$position 开始提取子串.
            如果$string 为"*"或"@",那么将提取从位置$position 开始的位置参数
        ${string:position:length}
            在string 中从位置$position 开始提取$length 长度的子串.
        expr substr $string $position $length
            在string 中从位置$position 开始提取$length 长度的子串.
    子串削除
        ${string#substring}
            从$string 的左边截掉第一个匹配的$substring
        ${string##substring}
            从$string 的左边截掉最后一个个匹配的$substring
        ${string%substring}
            从$string 的右边截掉第一个匹配的$substring
        ${string%%substring}
            从$string 的右边截掉最后一个匹配的$substring
    子串替换
        ${string/substring/replacement}
            使用$replacement 来替换第一个匹配的$substring.
        ${string//substring/replacement}
            使用$replacement 来替换所有匹配的$substring.
        ${string/#substring/replacement}
            如果$substring 匹配$string 的开头部分,那么就用$replacement 来替换$substring.
        ${string/%substring/replacement}
            如果$substring 匹配$string 的结尾部分,那么就用$replacement 来替换$substring.
    注意:
    expr    1-based indexing.


     
    小山丘 @ 2007-05-21 23:11

    并行接口的分类: SPP(标准并行接口) ,EPP(增强型并行接口),ECP(扩展型并行端口)
       标准并行端口(SPP)也是最早的端口定义,主要功能如下,1:并行端口提供了8个数据线以进行并行的字节传输,2:计算机能够通过数据线向打印机发送 选能信号,以通知打印机已经准备好接收数据,3:打印机招收到数据后,向计算机发送一个回应信号(NACK)。其各位信号线所代表的意义详见下表。
       增强型并行端口(EPP)的出现提供了一种更高性能的连接方式,并东路向下兼容所有在此之前存在的并行接口及外设。与SPP不同之处在于原来17个信号 中的重新定义,在这17个信号中,EPP使用了其中的14个信号进行传输,握手和选通,剩下的3个信号可以由外设设计者有来自定义。
      并行接口的大致结构:
         
    并行口一般有25个引脚,其中包括8位数据线,5位打印机状态线,4位控制线.下面将对这些引脚予以详细说明:
      (注:1:>出,表示由计算机发向打印机;入,表示由打印机发向计算机,
          2:>低电平有效信号用上划线或星号表示(如S7*),高电平有效信号则没有上划线或星号)
    引脚号
    名称
    数据位 寄存器
    数据方向
    定义
    1
    /STROBE
    C0*  
    选通信号,低电平有效信号,表明线上有数据到达.
    2
    D0
     DATA_1-DATA_8
     
     
     
    D1-D8
     
     
      八位数据线,只有在SPP指令下才有能输出数据.
     
     
     
     
    3
    D1
    4
    D2
    5
    D3
    6
    D4
    7
    D5
    8
    D6
    9
    D7
     
    10
    /ACK
     S6 Status
    应答,以插入低电平的形式出现,表明最后一个字符已招收完毕。
    11
    BUSY
    S7*
    Status
    繁忙通知,以插入高电平的方式出现,表明打印机处于忙状态不能再接收数据。
    12
    PE
    S5 Status
    没有打印机纸。
    13
    SELECT
     S4 Status
    选择输入,以插入高电平的方式出现,表明打印机处于在线待命状态。
    14
    AUTO FEED
     C1* Control
    自动馈送,低电平有效信号民,通知打印机对于每遇到一个回车进行自动换行。
    15
    /ERROR
    S3 Status
    错误,该信号由打印机发向计算机,表明打印机处于错误状态。
    16
    /INIT
     C2 Control
    初始化,低电平有效信号,该信号用来对打印机进行复位。
    17
    /SELIN
     C3* Control
    选择输入,低电平有效信号,表明已经选中的打印机。
    18
    GND
       
    ---
    信号接地
    19
    GND
       
    ---
    信号接地
    20
    GND
       
    ---
    信号接地
    21
    GND
       
    ---
    信号接地
    22
    GND
       
    ---
    信号接地
    23
    GND
       
    ---
    信号接地
    24
    GND
       
    ---
    信号接地
    25
    GND
       
    ---
    信号接地
    打印机常用端口: 对于LPT1:0X378 为数据发送地址,0X379为打印机状态地址,0X37A为计算机向打印机控制地址, 通常为了使程序具有通用性我们可以从注册表中取得这个地址,对于WINDOWS CE 而言,这个值被存储在{HKEY_LOCAL_MACHINE//DRIVERS//BUILTIN//PARALLEL//IOBASE}.然后我们就可以通过对此三个端口进行控制达到简单的并口编程的目的.
    下面是对打印机状态端口及打印机控制端口作一详细解释:
    控制端口:
    0x37A
    1
    1
    输入控制
    中断
    17线
    16 线
    14 线
    1 线
       这个0x37A计算机控制打印机的地址,可以产生对打印机进行控制的必要信号,可写,两高位(7和8)没什么用,第6位写1表示可以向并口输出数据。第 五位中断信号(IRQ EN),利用此信号线,驱动程序可以在STATUS端口信号(nAck)的帮助下,使用该信号对中断信号的产生与否进行控制。第 3,2,1,0位分别控制第17线,第16线,第14线和第1线。(可以控制它们的状态)具体作用可参见前表
    状态端口:
    0x379
    (S7)11 忙
    (S6)10应答
    (S5)12缺纸
    (S4)13联机
    (S3)15 错误
      S2
    S1 
    S0 
      0x379为打印机状态地址,可读,通过个端口打印机适配器可以很方便的读取打印机的状态。
    标记为S7的信号表示最高位,SO表示为最低位,只有S3-S7五个信号才是真正有用的信号。他们的具体信号功能解释如下:
    S7*(busy):打印机使用该信号表示打印机正处于忙状态,不能再接收数据。需要强调的是,该信号通过适配器板时,进行了反相处理,因此连接器上的低电平到微处理器时就变成了高电平。
    S6(nAck):当适配器发出选通信号时,打印机就会产生该信号作为响应。通常情况下,该信号是高电平,选通打印机之后,打印机首先把该信号设为低电平,然后再返回高电平。
    S5(PE):当打印机缺纸时,它就会产生一个这样的信号,通常情况下,该信号由打印机保持为低电平,打印机纸使用完之后,该信号就会变成高电平。
    S4(SELECT):当打印机恢复正常操作时,它就会插入一个高电平的该信号。当打印机处于无效状态时,访信号就会变成低电平。
    S3(NERROR):当打印机出现错误时就会产生这种邮错信号。产生出错的原因很多,如打印纸堵了或产生了内部错误。产生错误时该信号就会设置成低电平。
    以下为在Windows CE 下打印机各种状态时,所对应的状态寄存器的(AL)的值:
    1:>在没接入打印机时寄存器AL值为127,对应二进制是:1111111
    2:>打印机在缺纸灯不亮时寄存器AL值为144,对应二进制是:10010000
    3:>打印机在缺纸灯亮时寄存器AL值为 119;对应二进制值是:11101111
    4:>打印机在不缺纸的情况下寄存器AL值 223,对应二进制值是:11011111
    5:>打印机在没开机的情况下得到AH值为207,对应二进制值是:11001111 
    下面介绍对并口的编程控制:
    (编程控制示例)(为汇编代码)
    // 此段代码为并口向打印机进行写数据,并发送控制信息。
    #define LPT_CLEAR_MASK 0x40
    #define LPT_STROBE_HI 0x0D
    #define LPT_STROBE_LO 0x0C

    #define LPT_STATUS_BITS 0xF8
    #define LPT_BITS_INVERT 0x48
    #define LPT_NOTBUSY 0x80
    #define LPT_PAPEROUT 0x20
    #define LPT_SELECT 0x10
    #define LPT_NFAULT 0x08

    #define LPT_TimeOut 0x01

    void OutByte(ULONG dataport, BYTE databyte) {
    #if x86
    _asm {
    mov dx, word ptr [dataport]
    mov al, byte ptr [databyte]
    out dx, al
    out dx, al
    add dx, 2
    in al, dx
    and al, LPT_CLEAR_MASK
    mov cl, al
    or al, LPT_STROBE_HI
    out dx, al
    out dx, al
    out dx, al
    out dx, al
    or cl, LPT_STROBE_LO
    mov al, cl
    out dx, al
    }
    #else


    WRITE_PORT_UCHAR((PUCHAR)dataport,databyte);

    dataport+=2;
    databyte = (READ_PORT_UCHAR((PUCHAR)dataport) & LPT_CLEAR_MASK)
    | LPT_STROBE_HI;
    WRITE_PORT_UCHAR((PUCHAR)dataport,databyte);

    databyte = (READ_PORT_UCHAR((PUCHAR)dataport) & LPT_CLEAR_MASK)
    | LPT_STROBE_LO;
    WRITE_PORT_UCHAR((PUCHAR)dataport,databyte);

    #endif
    }
    // 此段代码为读取打印机当前状态。
    BYTE CheckStatus(unsigned port) {
    BYTE bRet;

    #if x86
    _asm {
    mov dx, word ptr[port]
    Checkme:
    in al, dx
    mov ah, al
    nop
    nop
    in al, dx
    cmp al, ah
    jnz Checkme
    and ah, LPT_STATUS_BITS
    xor ah, LPT_BITS_INVERT
    test ah, LPT_PAPEROUT or LPT_NFAULT
    jnz CS_HasError
    test ah, LPT_SELECT
    jz CS_HasError
    and ah, LPT_NOTBUSY
    jz CS_HasError
    xor eax, eax
    CS_HasError:
    mov [bRet],al
    }
    #else

    BYTE bStatus;
    do {
    bRet= bStatus= READ_PORT_UCHAR((PUCHAR)port);
    } while (bStatus != READ_PORT_UCHAR((PUCHAR)port));
    bStatus&= LPT_STATUS_BITS;
    bStatus^= LPT_BITS_INVERT;

    if (!(bStatus & (LPT_PAPEROUT | LPT_NFAULT)) &&
    (bStatus & LPT_SELECT) && (bStatus & LPT_NOTBUSY))
    bRet=0;
    #endif
    return bRet;
    }


     
    小山丘 @ 2007-05-21 23:01

    2在C语言中操作I/O接口
    2.1操作I/O接口的常用方法
    我们常用/usr/include/io.h或者内核源代码中的linux/linux/asm-i386/io.h中提供的方法来访问I/O接口,要在程序里使用这些方法,你指需要在你的程序的开始部分加上
    #include <asm/io.h>
    由于gcc的限制,你可能需要使用优化选项,像这样:gcc -01(或更高),来编译你的代码,或者在#include<asm/io.h>前面加上#define extern static,然后加上#undef extern
    为了除错方便,如果你用的是新版本的gcc,你可以使用gcc -g -0,但优化后的代码在除错时可能会遇到许多不必要的麻烦,所以你可以将进行I/O操作的那些代码放到另外的文件中使用优化选项进行编译,然后再和其他不直接使用I/O操作的部分连接。
    操作权限:
    当你访问某些端口时,你必须让你的程序获得足够的权限,你可以通过使用函数ioperm()来实现(包含在unistd.h中,而且在内核中有定义),在 你进行I/O操作之前,你需要先使用此函数得到访问某些端口的权限,使用的方法是ioperm(from,num,turn_on),其中from是需要 操作的首个端口地址,num表示需要操作的后面几个端口的数目,例如ioperm(0x300,5,1)代表将使用从0x300到0x304共5个端口, 最后参数是一个布尔值(1代表true),1表示给程序申请权限,0表示收回访问权限,如果你需要操作多段不连续的端口,你可以多次使用这个函数,详细操 作请查看ioperm(2)的man手册。
    要使用ioperm()函数的话你需要拥有root权限,所以你需要用root用户运行此程序,或者获得root的权限,当你调用ioperm()取得权 限后你就可以放弃root权限了,但你不必在程序的最后使用ioperm(,,0)回收权限,因为程序结束后相应I/O操作权限会被系统自动回收。
    当你切换到普通用户时,程序的I/O操作权限不会被回收,但是如果你使用fork()创造一个新进程的话,由于新进程没有获得权限,所以系统会拒绝执行新创建的子进程中的I/O操作。
    ioperm()只能获得从0x000到0x3ff的I/O接口的权限,对于其他的端口,需要使用iopl(),这个函数可以获得所有I/O端口的访问权 限,同样在使用此函数前你需要root权限,现在你可以使用参数3来获得所有I/O接口的操作,ioperm(3),但是要小心,由于取得了系统中所有端 口的操作权限,你的错误的操作可能会造成难以预料的后果。
    开始操作端口:
    使用inb( <端口号> )来从端口输入一个字节(8个比特),这个函数的返回值就是从这个端口输入的数据。
    outb( <数值> , <端口号> )函数用来向端口送出数值。
    inw( <起始端口号> )从连续的两个读入一个字的数据(16个比特)。
    outw( <一个字长的数值> , <起始端口号> )向连续的两个端口打入一个字节的数据。
    如果你不能确定应该使用字节还是字,保守起见,你可以只使用inb()和outb(),大多数设备都可以支持端口的字节操作,每次端口操作都会占用至少一毫秒的时间。
    宏inb_p(),out_p(),inw_p()和outw_p()和上面介绍的函数功能相同,但会在端口操作后有大概1微秒的延时,你可以在 #include<asm/io.h>前面加上#define REALLY_SLOW_IO来延时4微秒,这些宏用通过向端口0x80写入数据的方法实现延时,延时的时间就是向0x80写入数据的时间(我们再后面会 提到这个端口),所以你必须在你的程序中使用ioperm()得到此端口的操作权限,但是如果你使用#define SLOW_IO_BY_JUMPING,就可以使用另外的方法而不用向0x80端口写数据,但此方法可能会导致错误。
    关于以上所提到的所有函数和宏定义已经在新版本的man手册中给出了详细资料。

    2.2访问端口的另外一种方法:/dev/port
    访问I/O接口的另外一种方法是使用open()函数来打开设备文件/dev/port,然后使用lseek()函数将指针移动到此文件的适当位置,例如 位置0处就是端口0x00,位置1就是端口0x01,等等,然后你就可以向里面用read()或write()函数写入或读出一个字节或者一个字。
    当然,进行上述操作需要你对/dev/port文件的读写权限,而且这种方法的运行效率相对要慢一些,但是此方法不需要编译器的优化选项和ioperm()函数,而且也不需要root权限,只要你有操作/dev/port的权限就可以了。
    你可以给所有用户对/dev/port的操作权限,这样就能使他们都能够调试I/O接口。但这会对系统安全造成一定的隐患,因为他们可以使用/dev/port文件来对硬盘,网卡等设备进行I/O操作,从而造成系统数据被窃听或者破坏。
    你不可以使用select()或者poll()来读/dev/port文件,如果数据被改变,系统上的硬件并不能通知CPU数据出错。

    3关于中断(IRQ)和DMA访问
    你不可以在你的用户级操作中使用中断和DMA,这需要事先编写一个驱动程序。
    但是你可以在用户级操作中关闭中断,虽然很危险。在你使用iopl()取得权限之后,你可以使用asm("cli")来关闭中断,然后用asm("sti")打开中断。

    4高级时间操作
    4.1延时
    首先,你不能保证你的程序能够完全遵守时间,因为Linux是一个多任务操作系统,在你的延时操作前后系统可能还会执行一些其他进程的操作,造成时间不 准。而且,也有可能多个程序会争用一个端口,但你可以将你的程序调至最高优先级(详情参看nice(2)的man手册)或者采用下文中介绍的实时处理。
    如果你需要比不同用户程序更精确的时间操作,你便可以考虑使用实时处理,Linux的2.x以上版本的内核已经开始支持这种方式,详细情况请参看sched_setscheduler(2)的man手册,也可以从http://luz.cs.nmt.edu/~rtlinux/得到更多的信息。

    延时函数:sleep()和usleep()
    现在介绍两个简单的时间操作,如果你要使用几秒的延时,最简单的方法是使用sleep()函数。而使用usleep()函数你可以延时若干个以10毫秒为 单位的时间。这两个函数并不使用使CPU空闲的方法实现延时,而是让CPU去执行其他进程。详细情况请参看sleep(3)和usleep(3)的man 手册页。

    在50毫秒以下的延时也会占用CPU比所指定的值更长的时间,80x86架构下的Linux的调度程序在返回你的程序之前,至少要花费10-30毫秒的时间,因此,在短时间的延时中,usleep()会比所指定的时间多延长时至少10秒。

    nanosleep()函数:
    从2.0.x版本开始内核就开始支持名叫nanosleep()的系统调用(详细情况请参看nanoslepp(2)的man手册),让你可以使用几微秒的超短延时时间。

    如果你将你的程序调到实时状态(使用sched_setscheduler()来切换),这时如要使用2毫秒以下的延时,nanosleep()就会使用完成一次循环的方法延时,或者也许会暂时像usleep()一样使程序休眠。

    这个延时循环使用的是系统调用udelay(),详细情况请查看/usr/include/asm/delay.h

    使用端口通信进行延时:
    使用微小延时另外一种方法是使用端口通信,向0x80写入或者读入一个字节的时间差不多是1微秒(这和你的CPU的处理速度无关),你可以多次使用这种方 法来延时几个微秒。这个操作在绝大多数系统中并不会造成任何伤害,所以内核中很多地方都使用这种方法(例如asm/io.h中)。

    实际上对0-0x3ff范围内的任意一个端口的操作都会使用差不多1微秒的时间,所以也可以使用向任何一个端口通信的方法来造成延时。

    使用汇编指令延时:
    如果你预先知道运行你的程序的机器的处理器型号和系统的时钟周期,这时就可以选择运行一些特定运行时间的汇编指令造成延时,但进程管理器很可能会在运行这组汇编指令过程中切换到其他进程,造成延时时间加长。
    如下表,处理器的速度会决定运行指令时的时钟周期,例如一个50MHz的处理器(如486DX-50或者486DX2-50)一个时钟周期为1/50000000秒,等于200毫微秒。
    指令 386机器的执行周期 486机器的执行周期
    xchg %bx,%bx 3 3
    nop 3 1
    or %ax,%ax 2 1
    mov %ax,%ax 2 1
    add %ax,0 2 1

    奔腾机的时钟周期和486机器大致相同,除了Pebtium Pro/II中,add %ax,0只使用1/2个时钟周期,这是因为它也许会和其他程序并行执行,这是因为在Pentium Pro中可以乱序和并行执行,这就是说在CPU执行程序时,后面的一条指令不一定要在前面指令后面执行。

    表中的nop和xchg两条指令除了延时之外不起任何作用,所以这是造成延时的最好方法,其他的指令会修改标志寄存器的内容,不过程序在编译时gcc会提醒你。

    如果你决定要使用使用这种方法,你可以在你的程序中使用asm(" <汇编语句> ")来,汇编语句的格式在上面的表中已经列出,如果你需要执行多条语句,你可以在asm中将它们用分号分隔开,例如asm("nop;nop"),执行两 条nop语句。

    注意:Intel x86架构的机器中不可以使用小于一个时钟周期的延时。

    奔腾机中的rdtsc指令:
    在奔腾机中,如果你要延时一定数目的时钟周期,可以使用rdtsc指令,下面就是使用这个功能所需的代码:
    extern __inline__ unsighed long long int rdtsc()
    {
    unsighed long long int x;
    __asm__ voatile (".byte 0x0f,0x31":"=A"(x))
    return x;
    }
    这样你就可以延时任意个时钟周期。

    4.2测量时间
    如果需要测量的时间精确到秒,最简单的方法时使用time()。如需要更加精确的话,可以使用gettimeofday(),这个函数可以精确到微秒,但同样这两个函数都可能会在进程调度中会出现偏差。
    如果你的进程需要在一定的时间之后得到一些信号,可以使用setitimer()或者alarm()详细使用方法请参看man手册页。

    5其他编程语言
    以上的例子全部是用C语言写成的,可以直接用到C++和Object C中。而且在汇编语言中你同样可以使用ioperm()或者iopl()函数。
    在其他编程语言中,最好是将关于端口通信的部分用C语言写成函数,编译后再将其和你用其他语言编写的程序连接起来。或者你也可以用你喜欢的程序设计语言直接读写/dev/port文件。

    6一些常用硬件端口
    如果你想使用一些常用的端口,比如打印机或者调制解调器,最好的方法是使用内核中附带的驱动程序,这样会省去很多时间,这节是为了那些希望向PC上连接一些非标准设备(比如一个小LCD显示屏,小电机或者其他一些什么东西)的人准备的。
    http://www.hut.fi/Misc/Electronics/�...��用资料。

    6.1并行端口
    并行端口/dev/lp0的基地址(下文称做BASE)是0x3bc,/dev/lp1是0x378,/dev/lp2是0x278,如果你只是想通过并口操纵打印机的话,请参看Printing-HOWTO。
    并行端口也可以通过ECP或EPP等扩展模式,实现数据双向传输,有关这方面的信息请参看http://www.fapo.com/和http://www.se...arallel.htm。
    需要注意的是,在用户模式下你不可以使用中断和DMA,如果你需要使用ECP或EPP,你必须编写一个驱动程序。
    端口BASE+1是只读的,它指示出并行接口的状态,下面便是它各个位表示的意义:
    第0,1位被保留
    第2位IRQ 中断状态
    第3位ERROR 错误显示位 (1有效)
    第4位 SLCT (1有效)
    第5位 PE (1有效)
    第6位ACK (1有效)
    第7位-BUSY 忙信号 (0有效)
    端口BASE+2是控制端口,你可以向其中写入控制信息,对这个端口的读操作会返回最近一次写入的数据,各个位的意义如下:
    第0位-STROBE (0有效)
    第1位-AUTO_FD_XT (0有效)
    第2位INIT (1有效)
    第3位-SLCT_IN (0有效)
    第4位 当这位置1时允许中断(ACK的上升沿表示中断)
    第5位 控制扩展模式的方向,0表示写,1表示读,而且只能向这位写数据,不可以读数据
    第6,7位被保留

    接脚定义(i表示输入,o表示输出)
    1io -STROBE 2io D0 3io D1 4io D2
    5io D3 6io D4 7io D5 8io D6
    9io D7 10i ACK 11i -BUSY 12i PE
    13i SLCT 14o -AUTO_FD_XT 15i ERROR 16o INIT
    17o -SLCT_IN 18-25 接地
    注意:机器在打开的状态下向并行接口连接设备可能会烧毁并行口,如果你需要反复实验的话你可以购买一块I/O卡,将它连接道电脑上后将卡上的并行接口的I/O地址调到一个空闲的地址。如果你不需要使用中断的话,IRQ的设置你可以不必关心。
    6.2游戏端口
    游戏端口的地址为0x200到0x207。如果你需要使用游戏杆的话,最好不要使用内核自带的驱动程序。
    游戏端口的接脚:
    1,8,9,15:+5V电源
    4,5,12 :接地
    2,7,10,14:数字信号输入,分别为BA1,BA2,BB1,BB2
    3,6,11,13:模拟信号输入,分别为AX,AY,BX,BY
    数字信号输入的信号来源是两个游戏杆上的各自两个按钮,你可以直接读取它们的状态,当按钮按下时返回低电平(0V),其他时候是高电平(5V)。
    //这里有一部分没有翻译

    6.3串行口
    类似RS-232的接口我们将其称做串行接口,Linux内核对这种接口支持得很完善,而且通用性也很好,可以很容易支持各种波特率的传输。详细情况请参看termio(3)的手册页和内核源代码中的linux/driver/char/serial.c,http://www.easysw.com/~mike/serial/�...��的资料。


     
    小山丘 @ 2006-09-22 16:45

    C语言中可变参数的用法

    我们在C语言编程中会遇到一些参数个数可变的函数,例如printf()
    这个函数,它的定义是这样的:
    int printf( const char* format, ...);
    它除了有一个参数format固定以外,后面跟的参数的个数和类型是
    可变的,例如我们可以有以下不同的调用方法:
    printf("%d",i);
    printf("%s",s);
    printf("the number is %d ,string is:%s", i, s);
    究竟如何写可变参数的C函数以及这些可变参数的函数编译器是如何实
    现的呢?本文就这个问题进行一些探讨,希望能对大家有些帮助.会C++的
    网友知道这些问题在C++里不存在,因为C++具有多态性.但C++是C的一个
    超集,以下的技术也可以用于C++的程序中.限于本人的水平,文中如果有
    不当之处,请大家指正.

    (一)写一个简单的可变参数的C函数

    下面我们来探讨如何写一个简单的可变参数的C函数.写可变参数的
    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;
    }
    我们可以在我们的头文件中这样声明我们的函数:
    extern void simple_va_fun(int i, ...);
    我们在程序中可以这样调用:
    simple_va_fun(100);
    simple_va_fun(100,200);
    从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:
    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)simple_va_fun(100,200);
    结果是:100 200
    3)simple_va_fun(100,200,300);
    结果是:100 200
    我们看到第一种调用有错误,第二种调用正确,第三种调用尽管结果
    正确,但和我们函数最初的设计有冲突.下面一节我们探讨出现这些结果
    的原因和可变参数在编译器中是如何处理的.

    (二)可变参数在编译器中的处理

    我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的,
    由于1)硬件平台的不同 2)编译器的不同,所以定义的宏也有所不同,下
    面以VC++中stdarg.h里x86平台的宏定义摘录如下(’\’号表示折行):

    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 )

    然后,我们用va_arg()取得类型t的可变参数值,以上例为int型为例,我
    们看一下va_arg取int型的返回值:
    j= ( *(int*)((ap += _INTSIZEOF(int))-_INTSIZEOF(int)) );
    首先ap+=sizeof(int),已经指向下一个参数的地址了.然后返回
    ap-sizeof(int)的int*指针,这正是第一个可变参数在堆栈里的地址
    (图2).然后用*取得这个地址的内容(参数值)赋给j.

    高地址|-----------------------------|
    |函数返回地址 |
    |-----------------------------|
    |....... |
    |-----------------------------|<--va_arg后ap指向
    |第n个参数(第一个可变参数) |
    |-----------------------------|<--va_start后ap指向
    |第n-1个参数(最后一个固定参数)|
    低地址|-----------------------------|<-- &v
    图( 2 )

    最后要说的是va_end宏的意思,x86平台定义为ap=(char*)0;使ap不再
    指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不
    会为va_end产生代码,例如gcc在linux的x86平台就是这样定义的.
    在这里大家要注意一个问题:由于参数的地址用于va_start宏,所
    以参数不能声明为寄存器变量或作为函数或数组类型.
    关于va_start, va_arg, va_end的描述就是这些了,我们要注意的
    是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.

    (三)可变参数在编程中要注意的问题

    因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢,
    可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能
    地识别不同参数的个数和类型.
    有人会问:那么printf中不是实现了智能识别参数吗?那是因为函数
    printf是从固定参数format字符串来分析出参数的类型,再调用va_arg
    的来获取可变参数的.也就是说,你想实现智能识别可变参数的话是要通
    过在自己的程序里作判断来实现的.
    另外有一个问题,因为编译器对可变参数的函数的原型检查不够严
    格,对编程查错不利.如果simple_va_fun()改为:
    void simple_va_fun(int i, ...)
    {
    va_list arg_ptr;
    char *s=NULL;

    va_start(arg_ptr, i);
    s=va_arg(arg_ptr, char*);
    va_end(arg_ptr);
    printf("%d %s\n", i, s);
    return;
    }
    可变参数为char*型,当我们忘记用两个参数来调用该函数时,就会出现
    core dump(Unix) 或者页面非法的错误(window平台).但也有可能不出
    错,但错误却是难以发现,不利于我们写出高质量的程序.
    以下提一下va系列宏的兼容性.
    System V Unix把va_start定义为只有一个参数的宏:
    va_start(va_list arg_ptr);
    而ANSI C则定义为:
    va_start(va_list arg_ptr, prev_param);
    如果我们要用system V的定义,应该用vararg.h头文件中所定义的
    宏,ANSI C的宏跟system V的宏是不兼容的,我们一般都用ANSI C,所以
    用ANSI C的定义就够了,也便于程序的移植.


    小结:
    可变参数的函数原理其实很简单,而va系列是以宏定义来定义的,实
    现跟堆栈相关.我们写一个可变函数的C函数时,有利也有弊,所以在不必
    要的场合,我们无需用到可变参数.如果在C++里,我们应该利用C++的多
    态性来实现可变参数的功能,尽量避免用C语言的方式来实现.

    写这篇文章时,适逢感冒,多得有她的关怀,谨把这篇文章献给她...


    原作者: kevintz


     
    小山丘 @ 2006-08-31 13:43

    The CentOS development team is pleased to announce the release of CentOS
    4.4 for i386 and x86_64.

    It is available on all CentOS.org mirrors and via bittorrent.

    This release corresponds to the upstream vendor U4 release together with
    updates through August 26th, 2006.

    The LiveCD version (1 cdrom) is available for i386.

    The work for the i386 and x86_64 ServerCDs and all other arches is in
    progress.

    If you are currently using another version CentOS-4, using this command
    will upgrade you to CentOS-4.4:

    yum update

    --------------------------------------------------------------------
    Major changes for this version are:

    Mozilla has been replaced by Seamonkey, Ethereal has been replaced by
    Wireshark.  Firefox and Thunderbird have moved from the 1.0.x to 1.5.x
    versions.  Openoffice.org has moved from the 1.1.2-x to the 1.1.5-x
    version.

    Please see the CentOS specific release notes here:
    http://mirror.centos.org/centos/4.4/os/i386/RELEASE-NOTES-en.html

    and the detailed release notes here:
    http://www.centos.org/docs/4/
    --------------------------------------------------------------------
    All previous released CentOS versions are available at:
    http://vault.centos.org
    --------------------------------------------------------------------
    To stay current with CentOS:

    Visit our website at http://www.centos.org

    Join the CentOS mailing list at:
    http://lists.centos.org/mailman/listinfo/centos

    Join various team members on IRC at irc.freenode.net #centos
    --------------------------------------------------------------------
    Note: It may take a couple days for some of the external mirrors to
    catch up.
    --------------------------------------------------------------------

    Enjoy,

    The CentOS Development Team


     
    小山丘 @ 2006-07-10 13:50

    Simple guide to use Vi
    The vi Text Editor.
    The vi text editor can be used to edit ASCII text files while you are working in a shell window. It is a standard editor found on most unix systems. To open or create a file in vi, from your command line type:
    vi filename
    If you are creating a new file, filename is what you want to call the file. If you are editing an existing file, type the current filename. The file appears in your shell window.
    Unlike most word processors you may be familiar with, vi has two modes of operation that you must toggle back and forth between in order to edit your files. One mode is for inserting text, and the other mode is for moving around or executing commands. The two modes are called:
      1. Text Input mode. (also called insert mode)
      2. Command mode (also called escape mode)
    When you first enter vi, you are in command mode, and cannot enter text until you change modes. You can switch to Text input mode by hitting the i key (for insert). After hitting the i key, any characters you type will be inserted at the current cursor position. Alternatively you could enter insert mode by pushing the a key (for append), and characters you type will be appended to the current cursor position. To get back to escape mode you push the escape key. You need to be in Command mode before you can quit out of a file. Short summary of vi Commands.
    Use the following commands in Command mode to cut, paste, and move around in the text. Use them also to switch from Command mode to Text Input mode. Remember to hit <Esc> or <CTRL 3> whenever you want to switch from Text Input mode to Command mode.
    Adding Text in vi
    Use these Command mode keystrokes to switch to Text Input mode (hit <Esc> or <CTRL 3> to return to Command mode):
    a           Add text after the cursor.
    A          Add text to the end of the current line.
    i            Insert text at the cursor.
    I           Insert text at the beginning of the current line.
    o          Open a new line below the current line and add text.
    O         Open a new line above the current line and add text.
    s          Substitute the letter underneath the cursor with letter you type, and insert text.
    S or c   Delete the current line and substitute it with text you type.
    R or C   Replace current text with text you type.
    Cutting and Pasting Text in vi
    Use these Command mode keystrokes to cut and paste text:
    x          Delete the letter beneath the cursor.
    dw        Delete the letter beneath the cursor and the rest of the word.
    # dw     Delete the following number of words, including the current word.
    D          Delete from the cursor to the end of the line.
    dd         Delete the current line.
    # dd      Delete the following number of lines, including the current line.
    yy          Copy or "yank" the current line.
    # yy       Copy or "yank" the following number of lines, including the current line.
    p          Paste the current copied or deleted letters, words, or lines after the cursor.
    J          Join the next line with the current line (erases a carriage return).
    u          Undo the last edit.
    .          Redo the last editing command.
    Moving Around in a vi Text File
    Use these Command mode keystrokes to move around within the file:
    j          Move down to the next line.
    k          Move up to the previous line.
    h          Move backward by letter.
    l          Move forward by letter.
    w         Move forward by word.
    b          Move backward by word.
    e          Move forward to the end of a word.
    CTRL F  Move forward to next screen.
    CTRL B Move backward to previous screen.
    CTRL D Move forward one-half of a screen.
    G          Move to the end of the file.
    # G       Move to the specified line number in the file.
    $          Move to the end of the current line.
    0          Move to the beginning of the current line.
    /          wordSearch for specified word.
    n          Search for next occurrence of specified word.
    N          Search for previous occurrence of specified word.
    Saving or Quitting vi
    Use these Command mode keystrokes to save or quit out of a file:
    :wq or ZZ          Save and quit out of the file.
    :w          Save the current file without quitting.
    :q          Quit if no edits have occurred.
    :q!          Quit without saving edits.
    VI高级命令集锦
    1.交换两个字符位置
    xp
    2.上下两行调换
    ddp
    3.把文件内容反转
    :g/^/m0/       (未通过)
    4.上下两行合并
    J
    5.删除所有行
    dG
    6.从当前位置删除到行尾
    d$
    7.从当前位置复制到行尾
    y$ 如果要粘贴到其他地方 p 就可以了
    由于vi 是建立在 EX 上的 所以 当键入 : 时就来到了 EX 命令状态
    8.
    :ab string strings
    例如 ":ab usa United States of America" ,
    当你在文见里插入 usa 时
    United States of America 就蹦出来了
    9.
    :map keys new_seq
    定义你当前 键盘命令
    10.
    :set [all]
    vi or ex  的编辑状态
    如 显示每行 :set nu
    11.
    在命令状态下,nyy表示拷贝从光标行起的下n行内容,p表示paste,可刚复制的内容粘贴在光标处的
    下面。
    12.
    单个字符替换用r,覆盖多个字符用R,用多个字符替换一个字符用s,整行替换用S
    13.
    :%s/old_word/new_word/g
    这个指令是于在整个文件中替换特定字符串  
    14.光标控制
    k:上移 nk 上移n行
    j:下移 nj 下移n行
    将光标移到第n行,按下 mk
    将光标移到第m行,按下 "ay'k
    即将第n到m的行存到a寄存器,以此类推,b,c........寄存器等
    这样就可以将你常用的需要复用的内容粘贴到不同的寄存器中以备用
    想粘贴到某处,直接将光标移到某地,按下 ‘ap 即可,以此类推,b,c........寄存器等
    在当前屏幕中
    H 跳到第一行
    M 跳到中间一行
    L 跳到最后一行
    15.
    表8-2 删除命令
    删除命令操作
    d l 删除当前字符(与x命令功能相同)
    d 0 删除到某一行的开始位置
    d ^ 删除到某一行的第一个字符位置(不包括空格或TA B字符)
    d w 删除到某个单词的结尾位置
    d 3 w 删除到第三个单词的结尾位置
    d b 删除到某个单词的开始位置
    d W 删除到某个以空格作为分隔符的单词的结尾位置
    d B 删除到某个以空格作为分隔符的单词的开始位置
    d 7 B 删除到前面7个以空格作为分隔符的单词的开始位置
    d) 删除到某个语句的结尾位置
    d 4) 删除到第四个语句的结尾位置
    d( 删除到某个语句的开始位置
    d } 删除到某个段落的结尾位置
    d { 删除到某个段落的开始位置
    d 7 { 删除到当前段落起始位置之前的第7个段落位置
    d d 删除当前行
    d /t e x t 删除从文本中出现“ t e x t”中所指定字样的位置,一直向前直到下一个该字样所出现的
    位置(但不包括该字样)之间的内容
    d fc 删除从文本中出现字符“c”的位置,一直向前直到下一个该字符所出现的位置(包括
    该字符)之间的内容
    d tc 删除当前行直到下一个字符“ c”所出现位置之间的内容
    D 删除到某一行的结尾
    d $ 删除到某一行的结尾
    5 d d 删除从当前行所开始的5行内容
    d L 删除直到屏幕上最后一行的内容
    d H 删除直到屏幕上第一行的内容
    d G 删除直到工作缓存区结尾的内容
    d 1 G 删除直到工作缓存区开始的内容
    修改命令操作
    c l 更改当前字符
    c w 修改到某个单词的结尾位置
    c 3 w 修改到第三个单词的结尾位置
    c b 修改到某个单词的开始位置
    c W 修改到某个以空格作为分隔符的单词的结尾位置
    c B 修改到某个以空格作为分隔符的单词的开始位置
    c 7 B 修改到前面7个以空格作为分隔符的单词的开始位置
    c 0 修改到某行的结尾位置
    c) 修改到某个语句的结尾位置
    c 4) 修改到第四个语句的结尾位置
    c( 修改到某个语句的开始位置
    c } 修改到某个段落的结尾位置
    c { 修改到某个段落的开始位置
    c 7 { 修改到当前段落起始位置之前的第7个段落位置
    c tc 修改当前行直到下一个字符c所出现位置之间的内容
    C 修改到某一行的结尾
    c c 修改当前行
    5 c c 修改从当前行所开始的5行内容
    .重复上一次修改!  
    表8-4 替换命令
    替换命令操作
    s 将当前字符替换为一个或多个字符
    S 将当前行替换为一个或多个字符
    5 s 将从当前字符开始的5个字符替换为一个或多个字符
    vi替换使用规则:
    :g/s1/s/s2/s3/g
    第一个g表示对每一个包括s1的行都进行替换,第二个g表示对每一行包括s1的行所有的s2都用s3替换
    s表示替换,s2是要被替换的字符串,他可以和s1相同(如果相同的话用//代替),s3是替换字符串
    16.
    fx
    往右移动到 x 字符上
    Fx
    往左移动到 x 字符上
    tx
    往右移动到 x 字符前
    Tx
    往左移动到 x 字符后
    (注意:以上四个命令中,其中x是键入的字符)
    ;
    分号,配合 f 和 t 使用,重复一次
    ,
    逗号,配合 f 和 t 使用,反方向重复一次
    17. vi 环境选项  Solaris ksh
    noautoindent            nomodelines                     noshowmode
    autoprint               nonumber                        noslowopen
    noautowrite             nonovice                        tabstop=8
    nobeautify              nooptimize                      taglength=0
    directory=/var/tmp      paragraphs=IPLPPPQPP LIpplpipnpbtags=tags /usr/lib/tags
    noedcompatible          prompt                          tagstack
    noerrorbells            noreadonly                      term=vt100
    noexrc                  redraw                          noterse
    flash                   remap                           timeout
    hardtabs=8              report=5                        ttytype=vt100
    noignorecase            scroll=11                       warn
    nolisp                  sections=NHSHH HUuhsh+c         window=23
    nolist                  shell=/bin/ksh                  wrapscan
    magic                   shiftwidth=8                    wrapmargin=0
    mesg                    noshowmatch                     nowriteany
    For C-Shell:
    setenv EXINIT "set nu"
    For Bourne or Korn Shell:
    EXINIT="set nu"; export EXINIT
    For Korn Shell Only (alternate method):
    typeset -x EXINIT="set nu"
    在 .profile 里设置 vi 的环境选项 , 以上均测试过
    18.标记文本
      mchar   用字母char标记当前光标的位置
      `char   移至char所标记处
      'char   移至char标记所在行的开头处
      "     移至当前行上一次所在位置(在光标移动之后)――一个双引号
      ''    移至当前行上第一次所在位置的行的开头处(在光标移动之后)――两个单引号
    19.
    同时vi多个文件时,CTRL-SHIFT-6回到上一个文件,在本次vi的文件和上次vi的文件之间切换。
    但是我发现一个BUG:在用CTRL-SHIFT-6切换到上一个文件后,用:args查看多文件vi状态时,
    屏幕底部仍然显示目前vi的是刚才的文件。
    (在HP-UX,Solaris,AIX上通过)
    也可以使用:
    :e#
    进行切换
    20.
    sco 下VI 要在文本前同样的字符加用
    %s/^/要加的内容/g      要在文本后同样的字符加
    %s/$/要加的内容/g  
    21.
    如何去掉文本中的 ^M 硬回车?不必用binary传回去再ascii传回来的方式,用shell或者unix语句实现。
    cat filename |tr -d '5' >newfile
    不同的unix系统还存在一些其他不同的命令,如:doscp
    sed 也可以实现这个功能.
    dos2unix filename filename2
    反之
    unix2dos filename filename2
    在vi 中用:$s/^M//g
    ^是crtl-V crtl-M  
    22.如何在“unix命令行”下将一个文件的某字符串用另一个串换掉
    sed 's/string1/string2/gp' file1 > file2
    23.将/etc/hosts下所有的地址都ping 2次
      1  #/usr/bin/sh
      2  #grad /etc/hosts and ping each address
      3  cat /etc/hosts|grep -v '^#' | while read LINE
      4  do
      5   ADDR=`awk '{print }'`
      6  for MACHINE in $ADDR
      7   do
      8     ping  $MACHINE -n 2
      9   done
     10  done  


     
    小山丘 @ 2006-06-06 13:10

    TagEclipse    插件                                          

    0.Eclipse下载
    EMF,GEF - Graphical Editor Framework,UML2,VE - Visual Editor都在这里下载
    http://www.eclipse.org/downloads/index.php
     
    0.5.lomboz J2EE插件,开发JSP,EJB
    http://forge.objectweb.org/projects/lomboz
    1.MyEclipse J2EE开发插件,支持SERVLET/JSP/EJB/数据库操纵等
    http://www.myeclipseide.com
     
    2.Properties Editor  编辑java的属性文件,并可以自动存盘为Unicode格式
    http://propedit.sourceforge.jp/index_en.html
     
    3.Colorer Take  为上百种类型的文件按语法着色
    http://colorer.sourceforge.net/
     
    4.XMLBuddy 编辑xml文件
    http://www.xmlbuddy.com
     
    5.Code Folding  加入多种代码折叠功能(比eclipse自带的更多)
    http://www.coffee-bytes.com/servlet/PlatformSupport
     
    6.Easy Explorer  从eclipse中访问选定文件、目录所在的文件夹
    http://easystruts.sourceforge.net/
     
    7.Fat Jar 打包插件,可以方便的完成各种打包任务,可以包含外部的包等
    http://fjep.sourceforge.net/
     
    8.RegEx Test 测试正则表达式
    http://brosinski.com/stephan/archives/000028.php
     
    9.JasperAssistant 报表插件(强,要钱的)
    http://www.jasperassistant.com/
     
    10.Jigloo GUI Builder JAVA的GUI编辑插件
    http://cloudgarden.com/jigloo/
     
    11.Profiler 性能跟踪、测量工具,能跟踪、测量BS程序
    http://sourceforge.net/projects/eclipsecolorer/
     
    12.AdvanQas 提供对if/else等条件语句的提示和快捷帮助(自动更改结构等)
    http://eclipsecolorer.sourceforge.net/advanqas/index.html
     
    13.Log4E Log4j插件,提供各种和Log4j相关的任务,如为方法、类添加一个logger等
    http://log4e.jayefem.de/index.php/Main_Page
     
    14.VSSPlugin VSS插件
    http://sourceforge.net/projects/vssplugin
     
    15.Implementors 提供跳转到一个方法的实现类,而不是接中的功能(实用!)
    http://eclipse-tools.sourceforge.net/implementors/
     
    16.Call Hierarchy 显示一个方法的调用层次(被哪些方法调,调了哪些方法)
    http://eclipse-tools.sourceforge.net/call-hierarchy/index.html
     
    17.EclipseTidy 检查和格式化HTML/XML文件
    http://eclipsetidy.sourceforge.net/
     
    18.Checkclipse 检查代码的风格、写法是否符合规范
    http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm
     
    19.Hibernate Synchronizer Hibernate插件,自动映射等
    http://www.binamics.com/hibernatesync/
     
    20.VeloEclipse  Velocity插件
    http://propsorter.sourceforge.net/
     
    21.EditorList 方便的列出所有打开的Editor
    http://editorlist.sourceforge.net/
     
    22.MemoryManager 内存占用率的监视
    http://cloudgarden.com/memorymanager/
     
    23.swt-designer java的GUI插件
    http://www.swt-designer.com/
     
    24.TomcatPlugin 支持Tomcat插件
    http://www.sysdeo.com/eclipse/tomcatPlugin.html
     
    25.XML Viewer
    http://tabaquismo.freehosting.net/ignacio/eclipse/xmlview/index.html
     
    26.quantum 数据库插件
    http://quantum.sourceforge.net/
     
    27.Dbedit 数据库插件
    http://sourceforge.net/projects/dbedit
     
    28.clay.core 可视化的数据库插件
    http://www.azzurri.jp/en/software/index.jsp
    http://www.azzurri.jp/eclipse/plugins
     
    29.hiberclipse hibernate插件
    http://hiberclipse.sourceforge.net
    http://www.binamics.com/hibernatesync
     
    30.struts-console Struts插件
    http://www.jamesholmes.com/struts/console/
     
    31.easystruts Struts插件
    http://easystruts.sourceforge.net
     
    32.veloedit Velocity插件
    http://veloedit.sourceforge.net/
     
    33.jalopy 代码整理插件
    http://jalopy.sourceforge.net/
     
    34.JDepend 包关系分析
    http://andrei.gmxhome.de/jdepend4eclipse/links.html
     
    35.Spring IDE Spring插件
    http://springide-eclip.sourceforge.net/updatesite/
     
    36.doclipse 可以产生xdoclet 的代码提示
    http://beust.com/doclipse/




    还有一些有用的URL
    http://www.open-open.com/04.htm
    http://jeva.bokee.com/4617937.html



     
    小山丘 @ 2006-05-30 15:41

    部分照片已经上传至http://www.flickr.com/photos/freecell_xu/ 
    太累了,以后有空了再写游记。



     
    小山丘 @ 2006-05-24 15:51

    Vim 7 is ready!  After years of development this feature packed editor
    is waiting for you.

    Since Vim 6.4 many new features have been added.  To mention a few:

    - Spell checking support for about 50 languages
    - Intelligent completion for C, HTML, Ruby, Python, PHP, etc.
    - Tab pages, each containing multiple windows
    - Undo branches: never accidentally lose text again
    - Vim script supports Lists and Dictionaries (similar to Python)
    - Vim script profiling
    - Improved Unicode support
    - Highlighting of cursor line, cursor column and matching braces
    - Translated manual pages support.
    - Internal grep; works on all platforms, searches compressed files
    - Browsing remote directories, zip and tar archives
    - Printing multi-byte text

    Once you have installed Vim 7.0 you can find details about the changes
    since Vim 6.4 with ":help version7".


    Credits
    -------

    A lot of people helped making Vim 7 possible by providing patches,
    suggestions, bug reports and proofreading the documentation.  You can
    find their names with ":help version7".  Many thanks to all of them!

    Also thanks to Vim sponsors who supported me while working on Vim 7.  I
    am now going back to a paid job.  Please continue sponsoring Vim.  The
    money now goes to help children in Uganda.  The more you help them the
    more I will feel obliged to work on Vim.  There is a drought right now,
    we need to help 200 families with food.  http://www.vim.org/sponsor/


    Where to get it
    ---------------

    Information about which files to download for what system:
            http://www.vim.org/download.php

    A list of mirror sites can be found here:
            http://www.vim.org/mirrors.php

    Downloading through ftp from:
            ftp://ftp.vim.org/pub/vim/

    Downloading through http from:
            http://ftp.vim.org/pub/vim/

    Using rsync:
            rsync://ftp.nl.vim.org/Vim

    Using Subversion:
            http://www.vim.org/subversion.php

    Anonymous CVS is five week behind and doesn't have Vim 7.0 yet.


    An overview of the files:

    UNIX:
    unix/vim-7.0.tar.bz2           sources + runtime files, bzip2 compressed

    VARIOUS:
    extra/vim-7.0-extra.tar.gz     extra (non-Unix) files
    extra/vim-7.0-lang.tar.gz      multi-language files
    doc/vim70html.zip              help files converted to HTML

    MS-WINDOWS:
    pc/gvim70.exe                  self-installing, includes all runtime files
    pc/vim70rt.zip                 runtime files
    pc/vim70lang.zip               files for translated messages and menus
    pc/gvim70.zip                  GUI binary for Windows 95/98/NT/2000/XP
    pc/gvim70ole.zip               GUI binary with OLE support
    pc/gvim70_s.zip                GUI binary for Windows 3.1 (untested)
    pc/vim70d16.zip                16 bit console version for MS-DOS
    pc/vim70d32.zip                console version for MS-DOS/Windows 95/98
    pc/vim70w32.zip                console version for Windows NT/2000/XP
    pc/vim70src.zip                sources for PC (with CR-LF)

    DIFFS TO PREVIOUS BETA
    unstable/unix/vim-7.0g-7.0.diff.gz           sources + runtime files
    unstable/extra/vim-7.0g-7.0-extra.diff.gz    extra files
    unstable/extra/vim-7.0g-7.0-lang.diff.gz     multi-language files

    SPELL FILES
    ftp://ftp.vim.org/pub/vim/runtime/spell/
    http://ftp.vim.org/pub/vim/runtime/spell/

    You should be able to do ":set spellang=xx" and Vim will offer you to
    download spell files for "xx".



    Mailing lists
    -------------

    For user questions you can turn to the Vim mailing list.  There are a
    lot of tips, scripts and solutions.  You can ask your Vim questions, but
    only if you subscribe.  See http://www.vim.org/maillist.php#vim

    If you want to help Vim development or get the latest patches, subscribe
    to the vim-dev mailing list.  See http://www.vim.org/maillist.php#vim-dev

    Subject specific lists:
    Multi-byte issues: http://www.vim.org/maillist.php#vim-multibyte
    Macintosh issues:  http://www.vim.org/maillist.php#vim-mac

    Before you ask a question you should search the archives, someone may
    already have given the answer.


    Reporting bugs
    --------------

    Send them to <bugs@...>.  Please describe the problem precisely.
    All the time spent on answering mail is subtracted from the time that is
    spent on improving Vim!  Always give a reproducible example and try to
    find out which settings or other things influence the appearance of the
    bug.  Try starting without your own vimrc file: "vim -u NONE".  Try
    different machines if possible.  See ":help bugs" in Vim.  Send me a
    patch if you can!

    If something needs discussing with other developers, send a message to the
    vim-dev mailing list.  You need to subscribe first.


    Happy Vimming!


     
    小山丘 @ 2006-02-07 16:39

          在大型的开发项目中,通常有几十到上百个的源文件,如果每次均手工键入 gcc 命令进行编译的话,则会非常不方便。因此,人们通常利用 make 工具来自动完成编译工作。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源 文件。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。实际上,make 工具通过一个称为 makefile 的文件来完成并自动维护编译工作。makefile 需要按照某种语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系。当修改了其中某个源文件时,如果其他源文 件依赖于该文件,则也要重新编译所有依赖该文件的源文件。makefile 文件是许多编译器,包括 Windows NT 下的编译器维护编译信息的常用方法,只是在集成开发环境中,用户通过友好的界面修改 makefile 文件而已。


    默认情况下,GNU make 工具在当前工作目录中按如下顺序搜索 makefile:

    * GNUmakefile

    * makefile

    * Makefile

    在 UNIX 系统中,习惯使用 Makefile 作为 makfile 文件。如果要使用其他文件作为 makefile,则可利用类似下面的 make 命令选项指定 makefile 文件:$ make -f Makefile.debug

    makefile 基本结构

    makefile 中一般包含如下内容:

    * 需要由 make 工具创建的项目,通常是目标文件和可执行文件。通常使用"目标(target)"一词来表示要创建的项目。

    * 要创建的项目依赖于哪些文件。

    * 创建每个项目时需要运行的命令。

    例 如,假设你现在有一个 C++ 源文件 test.C,该源文件包含有自定义的头文件 test.h,则目标文件 test.o 明确依赖于两个源文件:test.C 和 test.h。另外,你可能只希望利用 g++ 命令来生成 test.o 目标文件。这时,就可以利用如下的 makefile 来定义 test.o 的创建规则:

    # This makefile just is a example.
    # The following lines indicate how test.o depends
    # test.C and test.h, and how to create test.o

    test.o: test.C test.h
        g++ -c -g test.C

    从 上面的例子注意到,第一个字符为 # 的行为注释行。第一个非注释行指定 test.o 为目标,并且依赖于test.C 和 test.h 文件。随后的行指定了如何从目标所依赖的文件建立目标。当 test.C 或 test.h 文件在编译之后又被修改,则 make 工具可自动重新编译 test.o,如果在前后两次编译之间,test.C 和 test.h 均没有被修改,而且 test.o 还存在的话,就没有必要重新编译。这种依赖关系在多源文件的程序编译中尤其重要。通过这种依赖关系的定义,make 工具可避免许多不必要的编译工作。当然,利用 Shell 脚本也可以达到自动编译的效果,但是,Shell 脚本将全部编译任何源文件,包括哪些不必要重新编译的源文件,而 make 工具则可根据目标上一次编译的时间和目标所依赖的源文件的更新时间而自动判断应当编译哪个源文件。

    makefile 变量

    GNU 的 make 工具除提供有建立目标的基本功能之外,还有许多便于表达依赖性关系以及建立目标的命令的特色。其中之一就是变量或宏的定义能力。如果你要以相同的编译选项 同时编译十几个 C 源文件,而为每个目标的编译指定冗长的编译选项的话,将是非常乏味的。但利用简单的变量定义,可避免这种乏味的工作:

    # Define macros for name of compiler
    CC = gcc

    # Define a macr o for the CC flags
    CCFLAGS = -D_DEBUG -g -m486

    # A rule for building a object file
    test.o: test.c test.h
        $(CC) -c $(CCFLAGS) test.c

    在 上面的例子中,CC 和 CCFLAGS 就是 make 的变量。GNU make 通常称之为变量,而其他 UNIX 的 make 工具称之为宏,实际是同一个东西。在 makefile 中引用变量的值时,只需变量名之前添加 $ 符号,如上面的 $(CC) 和 $(CCFLAGS)。

    GNU make 的主要预定义变量

    一 个 makefile 文件中可定义多个目标,利用 make target 命令可指定要编译的目标,如果不指定目标,则使用第一个目标。通常,makefile 中定义有 clean 目标,可用来清除编译过程中的中间文件,例如:clean:rm -f *.o,运行 make clean 时,将执行 rm -f *.o 命令,最终删除所有编译过程中产生的所有中间文件。

    GNU make 有许多预定义的变量,这些变量具有特殊的含义,可在规则中使用。表 1 给出了一些主要的预定义变量,除这些变量外,GNU make 还将所有的环境变量作为自己的预定义变量。

     表 1  GNU make 的主要预定义变量

    预定义变量                      含义

    $*              不包含扩展名的目标文件名称。
    $+              所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。
    $<              第一个依赖文件的名称。
    $?              所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。
    $@             目标的完整名称。
    $^              所有的依赖文件,以空格分开,不包含重复的依赖文件。
    $%             如果目标是归档成员,则该变量表示目标的归档成员名称。例如,如果目标名称为 mytarget.so(image.o),则$@为 mytarget.so,而$%为 image.o。
    AR              归档维护程序的名称,默认值为 ar。
    ARFLAGS     归档维护程序的选项。
    AS              汇编程序的名称,默认值为 as。
    ASFLAGS     汇编程序的选项。
    CC              C 编译器的名称,默认值为 cc。
    CCFLAGS     C 编译器的选项。
    CPP             C 预编译器的名称,默认值为 $(CC) -E。
    CPPFLAGS    C 预编译的选项。
    CXX            C++ 编译器的名称,默认值为 g++。
    CXXFLAGS   C++ 编译器的选项。
    FC              FORTRAN 编译器的名称,默认值为 f77。
    FFLAGS       FORTRAN 编译器的选项。

    隐含规则

    GNU make 包含有一些内置的或隐含的规则,这些规则定义了如何从不同的依赖文件建立特定类型的目标。GNU make 支持两种类型的隐含规则:

    * 后缀规则(Suffix Rule)。后缀规则是定义隐含规则的老风格方法。后缀规则定义了将一个具有某个后缀的文件(例如,.c 文件)转换为具有另外一种后缀的文件(例如,.o 文件)的方法。每个后缀规则以两个成对出现的后缀名定义,例如,将 .c 文件转换为 .o 文件的后缀规则可定义为:

    .c.o:
    $(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $<

    * 模式规则(pattern rules)。这种规则更加通用,因为可以利用模式规则定义更加复杂的依赖性规则。模式规则看起来非常类似于正则规则,但在目标名称的前面多了一个 % 号,同时可用来定义目标和依赖文件之间的关系,例如下面的模式规则定义了如何将任意一个 X.c 文件转换为 X.o 文件:

    %.c:%.o
    $(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $<

    运 行 make我们知道,直接在 make 命令的后面键入目标名可建立指定的目标,如果直接运行 make,则建立第一个目标。我们还知道可以用 make -f mymakefile 这样的命令指定 make 使用特定的 makefile,而不是默认的 GNUmakefile、makefile 或 Makefile。但 GNU make 命令还有一些其他选项,表 2 给出了这些选项。

    表 2  GNU make 命令的常用命令行选项

    命令行选项              含义
    -C DIR              在读取 makefile 之前改变到指定的目录 DIR。
    -f FILE              以指定的 FILE 文件作为 makefile。
    -h                    显示所有的 make 选项。
    -i                     忽略所有的命令执行错误。
    -I DIR               当包含其他 makefile 文件时,可利用该选项指定搜索目录。
    -n                    只打印要执行的命令,但不执行这些命令。
    -p                    显示 make 变量数据库和隐含规则。
    -s                    在执行命令时不显示命令。
    -w                    在处理 makefile 之前和之后,显示工作目录。
    -W FILE            假定文件 FILE 已经被修改。



     
    小山丘 @ 2005-12-18 11:22


    一向是睡眠需要比别人低的人,从小就这样。小时候一到夏天就得午睡,算是我最痛苦的时间了。几乎没有睡懒觉的习惯,周末也不例外。甚至前两年还一直做个“早睡早起”的人---“早上睡,早上起”:)。可是,这两年,精力不如从前,已是不争的事实;从前熬个夜什么的,只要第二天早点睡,第三天铁定恢复;而现在好像好几天都不能重新回到100%。我自嘲说是“年纪大了”,朋友安慰说“因为从前习惯不好,把身体弄坏了。”虽然知道自己应该属于“猫头鹰”的类型,可是当猫头鹰也需要在白天上班,当猫头鹰要面对的是一群百灵鸟的时候,没办法,只好改良自己的习惯。同时,从03年底,便开始刻意的寻找可以提高白天工作效率的途径。睡眠是很重要的一环。

    今天在Steve Pavlina的Blog看到一篇文章,How To Become An Early Riser。很巧,这是这些日子我正在探索的问题,或者说,相当一段时间都在探索的问题。

    对于睡眠,Steve在他的文章中,正反各举出2点。

    关于睡眠错误的认识:
    1、每天必须在同一时间睡觉和起床。
    2、完全听从身体的指令,困了才睡,醒了才醒。

    关于睡眠正确的做法:
    1、困了才睡
    2、定时早起

    Steve认为,如果预定6点起床,即使早上3点才睡觉,也不要因此就睡懒觉,仍然6点起床。我们的身体会自我调节,第2天晚上通常会提前犯困,自然会早点休息了。

    自从5月1日搬家以来,为了每天早晨的公交车,多少改变了一些作息。有意思的是,竟与Steve的推荐不谋而合,晚上总是在12点以前睡觉,早上5:45-6:10起床,目前没有用闹钟。每天还不算太困。

    可是“不困”和“高效”是不同的概念。以自己的亲身实践,把Steve的理论补充一下:
    1、5天工作日中,至少选择一天比平常更早休息,我一般是周三或者周四。
    2、周日晚比正常时间更早休息。
    3、睡前不要饮刺激性酒水,尽量放松入眠。
    4、关于“猫睡”。
    一天中尽量找点时间可以“猫睡”(Cat Nap );丘吉尔、周恩来都深谙此道,一有空就闭上眼打个盹儿,在疲劳来临之前先做储备。Steve也提到这点,他说大脑好像电脑,一个短暂而有效的打盹儿,就好像释放负重的内存一样,“Mental Reboot”,我喜欢这个说法。从前有时候会在中午稍憩,这周开始尝试新方案,中午去健身房,运动之后洗个澡,下午感觉还是比较清爽的。这个猫睡的时间,我就放在早晨的公交车上,和偶尔下午工作时间,不过也就几分钟而已。
    4、关于“alpha波”。
    第一次接触alpha波的概念,是在《学习的革命》中。两位作者指出,当大脑处于“放松的警觉”(relaxed alertness)状态下时,脑电波活动以8-12周/秒的速度进行,即alpha波。这种状态很适合开始一项新的学习。可是,对于这个脑波,一直没有切身体会。03年有一段时间,研究过催眠和潜意识。当时下载了好些关于催眠的mp3和书籍。刚开始使用时,效果很好,可是并没有能坚持。但是,现在发现,那段时间的练习,并非毫无回报。事实上,现在可以很容易就进入到放松的状态,并且有一瞬间很像“放松的警觉”所描述的情形。我猜想这也许就是alpha波的状态。

    关于睡眠的科学,各种说法多如牛毛,可是也是非难辨。从前晚上睡觉前,总是喝一点红酒,可是又有资料说,任何酒精类饮料,都会加深大脑的不安定,也不知道究竟是不是,总归就断掉了。其实,我的神经已经够坚强,连黑咖啡对我都没什么用。网上也有很多资料。或许可以参考一下。

    1、科学认知睡眠 踏实睡个好觉
    2、测试你的睡眠IQ



     
    小山丘 @ 2005-12-16 15:08

    从网上找了一些文章,现在开始研究。