[C语言笔记]undefined behavior: sprintf/snprintf

Posted by 许高飞 on 四月 28th, 2009

 
对下面这样的写法,大家可能不陌生:

sprintf(buf, “%s foo %d %d”, buf, var1, var2);

使用这个语句的最初目的,是用来实现格式化字符处理版本的’strcat’。
但是这么写是有问题的,看下面这个例子:

1 #include
2 #include
3
4 int main(void)
5 {
6 char buf[20];
7
8 memset(buf, ‘\0′, sizeof(buf));
9 strcpy(buf, “FOO”);
10 snprintf(buf, sizeof(buf), “%s%s”, buf, “BAR”);
11 printf(”%s\n”, buf);
12
13 memset(buf, ‘\0′, sizeof(buf));
14 strcpy(buf, “BAR”);
15 snprintf(buf, sizeof(buf), “%s%s”, “FOO”, buf);
16 printf(”%s\n”, buf);
17 }

Read the rest of this entry »

单机版版本控制系统RCS

Posted by 许高飞 on 四月 23rd, 2009

RCS(Revision Control System)
一个相当相当古老的工具了。虽然协同开发时大家一般是用 CVS、SVN或者GIT 来做版本控制的工具,但是如果自己个人使用,只需要单纯的版本管理功能时,就没必要用CVS、SVN、GIT这些,RCS就够了。
使用版本管理工具,一开始可能会觉得不习惯,但是用久了,你一定会发现使用版本控制系统真是好处多多!
RCS使用相当简单,只有几个指令而已,大部份系统都有包含。
简单的使用方法就是这样:
1. 建立 RCS 数据库
先在想要保存的程序代码下的目录下建立一个叫 RCS 的目录
mkdir RCS
2. 将档案登入到RCS 数据库
ci filename
这时,RCS 会要你输入 log,就是记录你对这个版本有什么说名的地方,简单说几句就可以了,当然也可以不打,然后会给你一个初始的版本编号,应该是1.1。你会发现到,原来的档案不见了,而在 RCS 目录下多了一个叫做 filename,v 的档案,那个档案就是用来记录 filename 的版本演进史的。
3. 把档案取出来
档案不见了,那还有什么戏唱,能够放进去的,当然就一定可以拿出来:
最基本的用法是这样,会取出 filename 的最新版本。
co filename
但是,注意它的属性,是只读的喔,要加上 -l 的参数表示要 lock 才可以做修改的动作,修改完了,再把档案 checkin 回去就完成了版本更新的动作了,这时的版本编号应该是1.2。
另外,co -r filename可以取出指定的版本,但是其属性一定是只读的。
4. 把修改的档案存回RCS 数据库
还是一样,ci filename,不过可以加上 –u 的参数顺便 unlock,如果要继续编辑的话,要加上 –l ,不然会自动把原来目录下的档案删除。
5. 观看一个档案的修改记录
rlog filename
比较版本的差异
rcsdiff -r[version] filename

用C扩充Tcl命令

Posted by 许高飞 on 四月 7th, 2009

Tcl可以轻松地通过用C语言编写命令来进行扩展。一个用C编写的命令比具有同样功能的Tcl程序更有效。用C语言编写程序的另一个原因是,在Tcl中可能没有与C功能完全相同的函数。例如,购置了一台新的彩色扫描仪或者独立的输入设备,而这台设备是通过C程序接口来进行初始化和操作的,那么,如果在用户的终端中没有与之相匹配的程序借口,这台设备就不能在Tcl脚本中访问。

/* main.c */
#include

int AppInit(Tcl_Interp * interp)
{
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}

return TCL_OK;
}

int main(int argc, char *argv[])
{
Tcl_Main(argc, argv, AppInit);

return 0;
}


main.c 源程序

使用 “gcc -o main main.c -ltcl” 编译即可运行。
注意:编译时可能出现 “Cannot find -ltcl” 错误提示,这是表示libtcl.so库没找到,可能的原因之一是libtcl.so没有正确地链接到libtcl8.5.so(其中的8.5与具体安装的tcl版本有关),可以进入 “/usr/lib” 目录,执行 “ln -s libtcl8.5.so libtcl.so” 修复。
相关链接
Read the rest of this entry »

一个死循环的根本原因分析及解决办法

Posted by 许高飞 on 三月 24th, 2009

下面这段程序,假入输入数字回车,比如“1↓”,则正常;假入输入一个字母回车,比如“a↓”,则会陷入死循环。

1 /* foo.c */
2 #include
3
4 #define MIN 1
5 #define MAX 100
6
7 int main(void)
8 {
9 int i;
10
11 while (1) {
12 printf(”\rPlz input an interger number (between %d and %d): \n”, MIN, MAX);
13 scanf(”%d”, &i);
14
15 if (i < MIN || i > MAX) {
16 printf(”\rERROR: Your choice must be between %d to %d!\n”, MIN, MAX);
17 continue;
18 } else {
19 break;
20 }
21 }
22 printf(”\rINFO: Your choice is %d!\n”, i);
23
24 return 0;
25 }

foo.c源代码
Read the rest of this entry »

Tcl笔记:catch、info性能分析

Posted by 许高飞 on 十二月 17th, 2008

最近我发现一个情况:如果’catch’被触发,程序的(时间)开销非常惊人。

我一直是一个懒惰的程序员,所以经常写这样的代码:

# initialise ‘b’ so that we always have valid values (and we don’t
# forget it later on
set b “default”

# do something, eventually creating the variable ‘a’
# now, set b to a if it exists
catch { set b $a}

好了,以后不要这么写(或者只在你肯定’catch’被触发的几率非常非常小的情况下这么写)。

下面我附上一个小测试脚本,它表明:当变量a不存在时,上面这种方式比下面这种方式慢大约5倍。

if {[info exists a]} {set b $a}

只有在’catch’不被触发的情况下,它才比if结构快大约4倍。

Read the rest of this entry »


Copyright © 2008 且学且思录. All rights reserved.