Archive for 六月, 2009

这样的一个需求的实现

Posted by 机器人 on 29th 六月 2009 in php/javascript

需求:

一个表格的单元格所对应的坐标由字母组合而成,具体排列方式如下:

第  1  行: A          B         C          D           E      …..     Z
第  2  行:AA       AB      AC      AD        AE   …..    AZ
第  3  行: BA       BB       BC      BD        BE    …..    BZ


第 27 行:ZA       ZB       ZC       ZD        ZE  …..     ZZ
第 28 行:AAA   AAB    AAC   AAD   AAE …    AAZ
依次类推
….
….

分别由26个英方字母组合而成,而每一个单元格都由唯一的一个数字与其对应,如:1 对应第1行第一列的A,26对应第1行第26列的Z,27对应第2行第1列的AA,26 * 27 = 702对应第27行26列的ZZ,703对应第28行第1列的AAA,等等。

请编写一个函数,接受一个数字参数,然后返回该数字所对应的单元格的字母组合。

分析:

由上面的需求可知,表格只有26列,而行数没有限制,数字26对应Z,27则对应AZ了,从而可以看出,列只要到了26,再加1的话,行就需要扩展一位。所以可以把这个问题看成是求26进制数的问题,即,怎么将一个十进制转换成一个26进制数。

所以第一步只需要请求出给出数字所对应26进制数即可,对于求26进制的方式和求一个十进制数的二进制的方式类似,通过不停的求商取余,直接到最后的商为0,然后对余数取反。

第二步则是建立一个字母和数字的映射数组,然后将第一步所求得的26进制数映射成对应的字母即可。

大致实现方法如下:

$a = array();
$a = array();
do {
    $n = $num % 26;
    $num = (int)($num / 26);
    array_push($a,$n);
} while ($num != 0);
$a = array_reverse($a)

将所取得的余数全部放入数组,等求解结束后,再将保存余数的数据里的元素反转。

接下来选建立一个映射数组。

$map = array(
	 0 => 'Z', 1 => 'A', 2 => 'B', 3 => 'C', 4 => 'D',
	 5 => 'E', 6 => 'F', 7 => 'G', 8 => 'H', 9 => 'I', 
	10 => 'J',11 => 'K',12 => 'L',13 => 'M',14 => 'N',
	15 => 'O',16 => 'P',17 => 'Q',18 => 'R',19 => 'S',
	20 => 'T',21 => 'U',22 => 'V',23 => 'W',24 => 'X',
	25 => 'Y'
);

但很快就会发现一个这样的规律。
25 对应的26进制数为 0 25, 映射字母为 ZY
26 对应的26进制数为 1 0, 映射字母为 ZA
27 对应的26进制数为 1 1, 映射字母为 AA
702对应的26进制数为 1 1 0,映射字母为 AAZ
703对应的26进制数为 1 1 1,映射字母为AAA
由上面的分析结果,可知,下面两种情况的映射结果不正确。

1.所有能被26整除的数所对应的字母对应关系不正确,而这样的数在被转成26进制数时,最后一数都为0,次最后一位数为1。

2.所有第一行内的数字对应的十进制数也不正确,最高位都为0,如果把最高位的0去掉,对应关系就正确了。

对于第一种情况,仔细观察可以发现,数据不正确,是因为数字刚才被26整除,需要进位所引起的,如果把进的位再退一位,就会发现对应关系就看起来对多了,可能还是有些地方不对。
如:
本来26应该对应Z的,而现在对应的是ZA,假设上面的分析结果正确,那么先对26所对应的26进制数进行退位分析。26对应的26进制数为1 0,由上面可知,高位的1是由于数字刚好被整除进位引起的,所以需要对其进行退位减1。
1 0 -> 0 0。
同样的分析方法来分析 702。
1 1 0 -> 1 0 0。
似乎看来起来还是不正确,但我们再仔细一看就发现了,这里是由于进行两次进位引起的,所以也需要进行两次即位。即。
1 1 0 -> 1 0 0 -> 0 0 0.
这下看起来似乎就正确很多了。这里的结果似乎和第一行内的数字结果很相似,如果将最高位的0去掉,结果就正确了。
于是,暂时得出如下结论:
结论 1: 如果转换后的26进制数中有0,需要对其次高位减1,次高位不存在时,则不进行任何操作。
结论 2: 如果转换后的26进制数中最高位为0,则需要将该位删除。

对于上面的几特殊情况运行上面的两条结论:
就可以得出正确结论。

大致实现代码如下:

$cnt = count($a);
for ($i = 0; $i < $cnt; $i++) {
		//将0所在位的次高位减1
    if ($a[$i] == 0 && isset($a[$i+1])) {
        $a[$i+1] -= 1;
    }
    //映射字母
    $a[$i] = $map[$a[$i]];
}
//最高位为0时,将其删除。由于已经做了映射转换,0转换为了Z
if ($a[$cnt -1] == 'Z') unset($a[$cnt-1]);

结合上面的分析,完全实现如下:

function num2name($num) {
	$map = array(
		 0 => 'Z', 1 => 'A', 2 => 'B', 3 => 'C', 4 => 'D',
		 5 => 'E', 6 => 'F', 7 => 'G', 8 => 'H', 9 => 'I', 
		10 => 'J',11 => 'K',12 => 'L',13 => 'M',14 => 'N',
		15 => 'O',16 => 'P',17 => 'Q',18 => 'R',19 => 'S',
		20 => 'T',21 => 'U',22 => 'V',23 => 'W',24 => 'X',
		25 => 'Y'
	);    
    $a = array();
    do {
        $n = $num % 26;
        $num = (int)($num / 26);
        array_push($a,$n);
    } while ($num != 0);
    $cnt = count($a);
    for ($i = 0; $i < $cnt; $i++) {
        if ($a[$i] == 0 && isset($a[$i+1])) {
            $a[$i+1] -= 1;
        }
        $a[$i] = $map[$a[$i]];
    }
    if ($a[$cnt -1] == 'Z') unset($a[$cnt-1]);
    $a = array_reverse($a);
    return join("",$a);
}

测试代码

$d = array(702,703,25,3234,24,1324,314,128,2,41);
foreach($d as $v) {
    echo num2name($v)."\n";
}

测试如果

ZZ
AAA
Y
DTJ
X
AXX
LB
DX
B
AO

另外附上一种运用递归的实现方法。(网友提供)

function num2name($num) {
    //定义一个数组
    if($num==0) return '';
    $arr ='ZABCDEFGHIJKLMNOPQRSTUVWXY';
    $n = intval(($num-1)/26); //取得整数倍
    $m = $num%26; //取得余数
    $name = num2name($n).$arr{$m};
    return $name;
}

哈哈,好像这种方式简洁多了!
机器人 2009-06-29 16:16 于 北京 晴

关于vim映射快捷键的补充

Posted by 机器人 on 26th 六月 2009 in vim

前几天写了 vim执行php或者c/c++的快捷键,但有一个缺点,就是必需为不同的文件类型映射不一样的快捷键,如果所有文件都用F5来执行多好!!

感谢小黑同学今天的提醒,可以考虑用autocmd(自动命令)来实现,不同的文件类型,运行不同的映射机制。
配置如下:

autocmd! BufNewFile,BufReadPost  *.php nmap < F5 > < ESC >:w< cr >:!clear && php -q < C-R>%< cr >
autocmd! BufNewFile,BufReadPost  *.cpp nmap < F5 > < ESC >:w< cr >:!clear && g++ < c -R >% -o test && ./test< cr >
autocmd! BufNewFile,BufReadPost  *.c   nmap < F5 > < ESC >:w< cr >:!clear && gcc < c -R >% -o test && ./test< cr >

这样对php,c/c++都可以使用F5来执行。

机器人 2009-06-24 16:48 于 北京 晴

重定向的几个组合应用

Posted by 机器人 on 24th 六月 2009 in linux/server

cmd 2>file      把文件描述符2重定向到file,即把错误输出存到file中。

cmd > file 2>&1     把标准错误重定向到标准输出,再重定向到file,即stderr和stdout都被输出到file中

cmd &> file     功能与上一个相同,更为简便的写法。

cmd >& file     功能仍与上一个相同。

cmd > f1 2>f2     把stdout重定向到f1,而把stderr重定向到f2

tee files     把stdout原样输出的同时,复制一份到files中。

tee files     把stderr和stdout都输出到files中,同时输出到屏幕。

cmd >> file 把 stdout 重定向到 file 文件中(追加);

cmd 1> fiel 把 stdout 重定向到 file 文件中;

cmd > file 2>&1 把 stdout 和 stderr 一起重定向到 file 文件中;

cmd 2> file 把 stderr 重定向到 file 文件中;

cmd 2>> file 把 stderr 重定向到 file 文件中(追加);

cmd >> file 2>&1 把 stderr 和 stderr 一起重定向到 file 文件中(追加);

cmd < file >file2 cmd 命令以 file 文件作为 stdin,以 file2 文件作为 stdout;

cat <>file 以读写的方式打开 file;

cmd < file cmd 命令以 file 文件作为 stdin;

cmd << delimiter Here document,从 stdin 中读入,直至遇到 delimiter 分界符。

机器人 2009-06-24 14:56 于 北京 晴

vim执行php或者c/c++的快捷键

Posted by 机器人 on 23rd 六月 2009 in c/c++, linux/server, php/javascript, phpoo, vim

经常我们会编写一些测试代码,这些代码一般只是临时测试某一个函数,测试过后基本上就没什么用了。
如果使用IDE,这好办,基本上都有一些快速运行的键,比如在ZendStudio里,将代码编写好了以后,只需要按一下F5,就可以马上出来执行结果,而且这个文件都可以不用保存。

如果使用VIM来编写代码,可能很多朋友就会想了,有没有什么方法来建立一个快捷键,能快速的运行我们所编写的代码呢?!!
答案当然是肯定了的,不然也不会写这篇日志来讨论这个问题了。

在介绍方法之前,先来谈一下自己以前的执行方式吧!

先拿PHP来讲吧,最传统的方式就是将编写好的代码放在apache的根目录,然后通过浏览器来运行,或者使用php命令来运行php.可以使用php的r参数

hqlong@~$ php -r "echo 'hqlong';"

来快速测试,或者使用q参数

hqlong@~$ php -q test.php

来运行。

接下来讲怎么将vim支持一键执行。
大致原理是使用键盘映射,将快捷键映射到执行的命令。

在.vimrc中添加

nmap < F5 > < ESC >:!clear && php -q < C-R >%< cr >

即当我们按下F5时,就相当于执行了如下操作。
1.按下ESC,然后再按下:,进入vim命令行模式
2.执行clear清屏操作。
3.然后运行当前脚本。
4.最后执行回车操作.
下面有几个指令需要解释一下:
< C - R >%:得到当前文件的名字,包括路径.(按ctrl+r,然后再按%)

接下来可以测试一下.
vim /tmp/test.php

< ? php
    echo "hqlong";
?>

保存后,按F5,
就是快速的得出执行结果。

基于c/c++也同样可以做出映射来,比如我们用F6来执行C++代码。
那么就只需在.vimrc中添加

nmap < F6 > < ESC >:!clear && g++ < C-R >% -o test && ./test< cr >

这里如果我们测试如下代码。
vim test.cpp

# include < iostream >
using namespace std;
 
int main() {
     cout << "hqlong";
    return 0;
}

将会在当前上当下生成一个test可执行文件,并执行它。
所以的这一切都是由于nmap的强大映射功能。

希望对大家有所帮助,欢迎对不明白的地方进行讨论。
机器人 2009-06-23 22:59 于 北京 晴

几步搞定makefile文件的编写

Posted by 机器人 on 16th 六月 2009 in c/c++, linux/server

对于一个简单的程序。如下:
hello.c

#include < stdio.h>
int main() {
    printf("hello world\n");
    return 0;
}

可通过

~@ubuntu:~$ gcc hello.c -o hello

来进行编译。
当一个程序有3个文件时。假设有如下几个文件。
hello.c global.h global.c。
源码如下
hello.c

#include < stdio.h>
#include "global.h"
 
int main() {
    echo("hello\n");
    return 0;
}

global.h

void echo (char* str);

global.c

#include < stdio.h>
#include "global.h"
 
void echo (char* str) {
    printf("%s",str);
}

一般的编译方式如下

~@ubuntu:~$ gcc global.c hello.c -o hello

或者先编译再连接

~@ubuntu:~$ gcc -o global.c
~@ubuntu:~$ gcc global.o hello.c -o hello

我们也可以使用make命令来对它进行编译,不过这里需要一个makefile文件来描述make为何种方式来编译源代码和链接程序。
makefile文件的缩写规则如下:
TARGET… : PREREQUISITES…
COMMAND


target:规则的目标
prerequisites:规则的依赖
command:规则的命令行。值得注意的是每一个命令必需是以[TAB]开始。
上面的程序的makefile简单编写如下
Makefile

hello:global.o hello.o
    gcc hello.o global.o -o hello
hello.o:hello.c global.h
    gcc -c hello.c -o hello.o
global.o:global.c global.h
    gcc -c global.c -o global.o
clean:
    rm *.o hello

使用make编译

~@ubuntu:~$ make
gcc -c global.c -o global.o
gcc -c hello.c -o hello.o
gcc hello.o global.o -o hello

这里我们可以发现当前目录下生成了hello这个可执行文件。

从上面的Makefile文件中,能看出有三条规则,第一条的目标就生成可执行文件hello,第二条目标就生成hello.o文件,第三条则是生成global.o文件。而每个冒号后台的部分为生成达到该目标所需要的依赖文件,比如:第一条需要依赖hello.o和global.o这两个文件,第二条需要依赖hello.c和 global.h这两上文件,第三条需要依赖global.c和global.h这两上文件。接下来下面每条规则下面的一行就是需要执行的命令了。

最后还有一个clean,当用户键入make clean时,就清除所有的*.o文件。

关于make使用上面Makefile文件的工作原理如下:
默认情况下,make执行的是Makefile文件中的第一个规则,此规则的目标也就是整个程序的终极目标,我们上面的文件中生成hello这个可执行文件就是我们的最终目标,但要生成hello,又必需要依赖于hello.o和global.o这两个链接文件,make在处理这个规则之前,需要先处理hello所依赖文件的更新规则。
对这些.o(链接文件)规则的处理有三种情况。
1. 目标.o文件不存在,使用其描述规则创建它。如:如果hello.o不存在,则使用gcc -c hello.c -o hello.o来创建它。
2. 目标.o文件存在,但它所信赖的源文件中的任何一个比它都要新,则使用其描述规则创建它。如:hello.c或者global.h有更新时,gcc -c hello.c -o hello.o就得重新执行一次。
3. 目标.o文件存在 ,但它比所依赖的所有源文件都要新时,则什么也不做。

完成了对所有的.o文件的创建和更新后,make将处理第一条规则(终极目标),同样也分三种情况下进行处理。
1. 目标文件”hello”不存在,则执行描述规则创建hello.
2. 目标文件”hello”存在,但它所信赖的文件中的任何一个比它都要新,则根据规则重新链接生成hello文件.
3. 目标文件 “hello”存在,它比它的任何一个链接文件都要新,则什么也不做.

更多细节可参考:
GNU make 中文手册
http://www.diybl.com/course/3_program/c++/cppjs/2008622/127546.html

机器人 2009-06-16 14:17 于 北京 雨

linux c/c++ socket程序的编写

Posted by 机器人 on 14th 六月 2009 in linux/server

这篇日志还是先从一个能够运行起来的例子出发,一旦能顺利的看到程序的成功运行,那么接下来的事件我想应该是问为什么了?似乎这样更加容易理解和掌握。

对于socket程序的概念这里就不多写了,但我相信,如果能看完这整篇文章,我相信不会再有这样的疑问的。

下面将编写一个c/s结构的程序,主要功能是client将向server发送一些消息,而当server收到client的请求时,并向client发送一条回应信息。

server.c代码如下:

#include <stdio .h>
#include < stdlib .h>
#include < errno .h>
#include < string .h>
#include < sys /types.h>
#include < netinet /in.h>
#include < sys /socket.h>
#include < sys /wait.h>
 
#define SERVPORT 3333 
#define BACKLOG 10
#define MAXSIZE 1024
 
int main() {
    int sockfd,client_fd;
    struct sockaddr_in my_addr;
    struct sockaddr_in remote_addr;
    //创建套接字
    if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) {
        perror("socket create failed!");
        exit(1);
    }
 
    //绑定端口地址
    my_addr.sin_family      = AF_INET;
    my_addr.sin_port        = htons(SERVPORT);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(my_addr.sin_zero),8);
    if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind error!");
        exit(1);
    }
 
    //监听端口
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen error");
        exit(1); 
    }
 
    while (1) {
        int sin_size = sizeof(struct sockaddr_in);    
        if ((client_fd = accept(sockfd, (struct sockaddr*)&remote_addr,&sin_size)) == -1) {
            perror("accept error!");
            continue;
        }
        printf("Received a connection from %s\n", (char*)inet_ntoa(remote_addr.sin_addr));
 
       //子进程段
        if (!fork()) {
            //接受client发送的请示信息
            int rval;
            char buf[MAXSIZE];   
            if ((rval = read(client_fd, buf, MAXSIZE)) < 0) {
                perror("reading stream error!");
                continue;
            }
            printf("%s\n",buf);
 
            //向client发送信息
            char* msg = "Hello,Mr hqlong, you are connected!\n";
            if (send(client_fd, msg, strlen(msg), 0) == -1) perror("send error!");
            close(client_fd);
            exit(0);
        } 
        close(client_fd);
    }
    return 0;
}

编译并启动服务

hqlong@ubuntu:~$ gcc server.c -o server
hqlong@ubuntu:~$./server &

这里我们的server已经作为一个服务后台运行,如果想知道后台的服务的运行状态,可能使用netstat来查看.

hqlong@ubuntu:~/t$ netstat -nl | grep 3333
tcp        0      0 0.0.0.0:3333            0.0.0.0:*               LISTEN

可以看出3333端口已经在监听,这说明服务已经启动。
为了测试server是否可以接受client的请求,可以使用telnet来进行测试。

hqlong@ubuntu:~$ telnet 127.0.0.1 3333
Trying 127.0.0.1...
Received a connection from 127.0.0.1
Connected to 127.0.0.1.
Escape character is '^]'.
test
test
 
Hello,Mr hqlong, you are connected!
Connection closed by foreign host.

可以看出,我们使用telnet来连接刚所启动的server,然后向该server发送了一条信息”test”,server收到了这条信息后,向client发送了一条响应信息,告诉我们,我们已经连接上了。

接下来来编写自己的client程序,完成的功能和上面的telnet的测试功能一样,向server发送一条信息,server在收到这条信息后,向client发送一条响应信息。
代码如下:client.c

#include < stdio .h>
#include < stdlib .h>
#include < errno .h>
#include < string .h>
#include < sys /types.h>
#include < netinet /in.h>
#include < sys /socket.h>
#include < sys /wait.h>
 
#define SERVPORT 3333
#define MAXDATASIZE 100
#define SERVER_IP "127.0.0.1"
#define DATA  "this is a client message"
 
int main(int argc, char* argv[]) {
    int sockfd, recvbytes;
    char buf[MAXDATASIZE];
    struct hostent *host;
    struct sockaddr_in serv_addr;
 
    if (( sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket error!");
        exit(1);
    }
    bzero(&serv_addr,sizeof(serv_addr));
    serv_addr.sin_family    = AF_INET;
    serv_addr.sin_port      = htons(SERVPORT);
    serv_addr.sin_addr.s_addr= inet_addr(SERVER_IP);
 
    if (connect(sockfd, (struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) == -1) {
        perror("connect error!");
        exit(1);
    }
 
    write(sockfd,DATA, sizeof(DATA));
   if ((recvbytes = recv(sockfd, buf, MAXDATASIZE,0)) == -1) {
        perror("recv error!");
        exit(1);
    }
 
    buf[recvbytes] = '\0';
    printf("Received: %s",buf);
    close(sockfd);
    return 0;
}

编译运行

hqlong@ubuntu:~$ gcc client.c -o client
hqlong@ubuntu:~$ ./client
Received a connection from 127.0.0.1
Hello,Mr hqlong, you are connected!
Connection closed by foreign host.

以上就是整个服务器端和客户端程序的编写。


上图显示了程序使用面向连接协议(tcp)时,进行的典型socket系统调用。服务器程序建立了一个socket,并调用bind函数将此socket和本地协议端口联系起来,然后用listen和accept函数将此socket参数置于被动的监听模式并接收到建立连接。
客户程序也建立一个socket,接着调用connect函数启动网络对话。在客户和服务器建立连接以后,就可以用read、write等函数进行通信了。
具体函数细节请参考linux c函数手册
http://man.chinaunix.net/develop/c&c++/linux_c/default.htm

机器人 2009-06-14 18:04 于 北京 晴

linux c/c++多线程程序的编写

Posted by 机器人 on 8th 六月 2009 in c/c++, linux/server

第一次尝试编写linux下多线程程序,也是颇废一番周折。深知初学者对能快速的成功运行一段程序的渴望,所以本文专门用了“linux c/c++多线程程序的编写“这个醒目的标题,方便大家能即使从搜索引擎搜到本文,从而提升大家的信心。
首先先让代码进行起来再说为什么,见了效果再回过来头来看原因似乎会容易明白和理解一些。
测试代码如下:

#include[stdio.h]
#include[unistd.h]
#include[stdlib.h]
#include[pthread.h]
#include[string.h]
void *thread_function(void* arg);
char message[] = "Hello world!";
 
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
 
    res = pthread_create(&a_thread, NULL, thread_function, (void*)message);
    if (0 != res) {
        perror("Thread creation faied");
        exit(EXIT_FAILURE);
    }
 
    printf("Waiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (0 != res) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined, it returned %s\n", (char*)thread_result);
    printf("Message is now %s\n",message);
    exit(EXIT_FAILURE);
}
void *thread_function(void* arg) {
    printf("thread_function is running. argument was %s\n",(char*)arg);
    sleep(3);
    strcpy(message,"bye!");
    pthread_exit("Thank you for the cpu time");
}

请将包含头文件的[替换成< ,]替换成>,代码高亮插件会认为尖括号是html标签,所以这里用中括号暂时替代。
编译:

hqlong@ubuntu:~/code/c$ gcc test.c -o test -lpthread

运行

hqlong@ubuntu:~/code/c$ ./test

结果

thread_function is running. argument was Hello world!
Waiting for thread to finish...
Thread joined, it returned Thank you for the cpu time
Message is now bye!

创建进程主要是通过pthread_create()这个函数来创建,函数的定义如下:

int pthread_create
(
	pthread_t *restrict tidp,
	const pthread_attr_t *restrict attr,
	void *(*start_rtn)(void),
	void *restrict arg
);

返回值:若是成功建立线程返回0,否则返回错误的编号
形式参数:
pthread_t *restrict tidp 要创建的线程的线程id指针
const pthread_attr_t *restrict attr 创建线程时的线程属性
void* (start_rtn)(void) 返回值是void类型的指针函数
vodi *restrict arg start_rtn的行参

注意上面还用到了pthread_join()这个函数,那么这个函数有什么用呢?接下来还是先看看它的原形定义:

int pthread_join
(
	pthread_t thread,
	void **value_ptr
);

各参数说明如下:
thread 等待退出线程的线程号
value_ptr 退出线程的返回值。
该函数的作用使得当前进程挂起,等待另一个进程返回才继续执行。也就是说当程序运行到这个地方时,程序会先停止,然后等线程id为thread的这个线程返回,然后程序才会断续执行。

在上面的例子中,如果把

  res = pthread_join(a_thread, &thread_result);
    if (0 != res) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined, it returned %s\n", (char*)thread_result);

注释掉,那么主程序根据不会等待线程返回,就退出,当然主进行退出了,他所创建的子进程也就会跟着退出,所以在上面的例子中,程序还在睡眠时,就被主进程强行退出了。

在上面例子进对源码进行编译时,加了-lpthread,如果不加-lprhead,会出现如下编译错误。

tmp/ccnPVTWo.o: In function `main':
mthread.c:(.text+0x30): undefined reference to `pthread_create'
mthread.c:(.text+0x6f): undefined reference to `pthread_join'
collect2: ld returned 1 exit status

thread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a。

更多细节请参考:
http://hi.baidu.com/wenlongren/blog/item/4615450f498006eaaa645759.html
http://hi.baidu.com/wenlongren/blog/item/998f04dd7e866de877c6383e.html
http://blog.sina.com.cn/s/blog_5dcf190f0100dbcm.html
http://hi.baidu.com/beisika/blog/item/8ced51cea7ac9c3eb600c8ea.html

机器人 2009-06-08 18:00 于 北京 阴
机器人 2009-06-09 10:48 于 北京 晴 更新

vim函数跳转技巧

Posted by 机器人 on 8th 六月 2009 in vim

跳转到函数、变量定义处:
[+ctrl+i 跳转到函数、变量和#define
[+ctrl+d 跳转到#define处
ctrl+i 向前跳到前几次光标位置
ctrl+o 向后跳到后几次光标位置

函数体跳转:
[[
]]
[]
][
{}

2009-07-07 17:31 补充

如何选中括号中的内容 进行:
将光标移至括号内,按shift+v进入行选模式,然后

i{ - 选小括号中内容,不包括小括号
a{ - 选小括号中内容,包括小括号
ib - 选中括号中内容,不包括括号
ab - 选中括号中内容,包括括号
i{ - 选大括号中内容,不包括大括号
a{ - 选大括号中内容,包括大括号

:h text-objects

下面还有些相关的tips,未全部验证:
vi{ 选中{}中间的内容,不包括{}
va{ 选中{}中间内容,包括{}
vi( 选中()中间内容
vi< 选中<>中间内容
vi[ 选中[]中间内容
vit 选中中间的内容
vi” 选中”"中间内容
vi’ 选中”中间的内容
vis 选中一个句子
vib 选中一个block
viw选中一个单词
vip 选中一个段落

机器人 2009-06-08 14:06 于 北京 雨

删除文件夹下所有.svn文件

Posted by 机器人 on 8th 六月 2009 in linux/server

方法一:

find . -name .svn | xargs rm -rf

方法二:

ls -alR | grep .svn/ | xargs rm -rf

机器人 2009-06-08 10:57 于 北京 雨

最近的事

Posted by 机器人 on 3rd 六月 2009 in mylife

项目停止……
人员调整……
没了。

机器人 2009-06-03 22:46 于 北京