经常需要远程登录到Linux服务器上改配置、写程序,我使用的编辑器是vim。vim它小快灵,网络速度慢也能工作,并且vim+ctags+cscope的组合能很好的满足编程的时候经常用到的代码跳转功能,比如查看函数原型、符号智能补全、查找符号被引用处等。 但ctags为系统提供的头文件生成的索引总是不太对。比如对于/usr/include/sys/socket.h,里面有很多函数在ctags处理的时候没有能加到索引里去。最后发现是__TRHOW的问题。以listen函数为例,在socket.h中,它的原型是: extern int listen (int __fd, int __n) __THROW; socket.h间接包含了sys/cdefs.h,__THROW就是在这个头文件中被定义的。其定义如下: # if !defined __cplusplus && __GNUC_PREREQ (3, 3) # define __THROW __attribute__ ((__nothrow__)) # define __NTH(fct) __attribute__ ((__nothrow__)) fct # else # if defined __cplusplus && __GNUC_PREREQ (2,8) # define __THROW throw () # define __NTH(fct) fct throw () # else # define __THROW # define __NTH(fct) fct # endif # endif 如果gcc正在编译c++文件,并且gcc版本大于2.8那么__THROW会被定义为throw()。如果正在编译c文件并且gcc版本在2.8之前,__THROW则是一个空的宏定义,如果版本大于3.3,则__THROW被定义成一个attribute内包含的nothrow的形式。最后这个形式表示这段c代码不会抛出异常。 正是这个复杂的宏定义干扰了ctags,对于所有像listen这样含有__THROW的原型,ctags一律都不能正确解析。其原因是ctags本身不是一个编译器也没有专门的预处理器,它是通过直接解析源文件的语法来工作的,不进行语义的检查和宏展开。对于宏,它的能力仅限于识别定义、调用和简单的条件编译的猜测。 为了不让__THROW干扰ctags,需要在运行ctags时使用-I选项。我一般使用下面的命令生成系统头文件tags ctags -I __THROW --file-scope=yes --langmap=c:+.h --languages=c,c++ --links=yes --c-kinds=+p -R -f ~/.vim/systags /usr/include /usr/local/include 其关键是-I __THROW部分和--c-kinds=+p部分。设置-I后,ctags会在处理文件时,就会忽略-I后面写出来的符号。而--c-kinds=+p则告诉ctags需要为函数原型的声明也生成tag。--langmap=c:+.h表示.h视为c文件而不是c++文件。 最后,设置你的~/.vimrc,加入一行: set tags+=~/.vim/systags 就可以享受系统库函数名补全、原型预览等功能了。 以前一直用Visual Studio写程序,这些功能都是已经有了的,不需要自己配置。在VIM里使用ctags、cscope和taglist插件和适当的配置一样可以达到同样的效果,而且有写地方还更方便了。 下面贴几幅图(点击查看大图): 这是对listen的预览窗口加智能补全的效果。当光标停在“e”上,VIM自动寻找“liste”开头的符号供你选择。对于“->”和“.”符号,VIM也可以对结构体成员进行智能补全。顶部的区域就是预览窗口,一般写代码的时候,它是关闭的,需要查看函数原型或者定义的时候,可以让它打开,很方便。
 下面是查看所有调用了recv函数的地方。我使用了quickfix窗口来显示查找的结果,就是图下部的窗口,可以在这个窗口里进行选择,按回车后自动跳到对应的位置。右侧的则是当前文件中的符号列表,包括宏、结构体、函数。可以在右边窗口中选择,并跳转,很方便。

下面是在VIM中直接调用make来编译程序的效果,我故意写错一个地方,gcc报告错误,VIM能够识别gcc的报告并且自动跳转到代码的错误行。我一般都习惯用quickfix窗口在错误列表选择一个错误并用回车跳转过去。

这是在VIM中直接调用man查看系统的帮助。看完以后把man窗口关掉就行了。

VIM中正在编辑的是我写的同时支持IPv6、IPv4的http、https代理的代码。这个程序支持为v6客户代理访问v4、v6网络,也为v4客户代理访问v4、v6网络,支持多个客户多个线程同时工作。这是我为了练习写IP协议无关程序而做的小项目。等有时间把这个代理完善一下再写一篇博。
|