Tips 2013-02-17

如果有需要把工程从Linux下面移植一份到Windows下,却又不熟悉Visual Studio的各种配置,那么用CMake来管理工程是一个不错的选择。从Makefile改写CMakeLists.txt并不麻烦,而且CMake可以自动生成VS的工程文件,很好用。 用 floor 和 ceil 这类函数最好先对参数做显示的类型转换,否则VS会报错。 isinf 和 isnan 能不能则不用,VS没有现成好用的对应版本。 关于把一份Git工程同步到SVN的版本库里去的方法,网上讨论的很多,比如这个: http://stackoverflow.com/questions/661018/pushing-an-existing-git-repository-to-svn 但是如果你的Git的工程已经有了悠久历史,那么在rebase那一步你可能会有非常多的conflicts要处理。一个小办法是每次出现了冲突都用这一行代码: $git checkout . –theirs && git add . && git rebase –continue 当然前提是当前目录下面没有不在git管理下的其他文件。这个虽然不解决根本问题,但是会方便很多。 总是有想要重构自己实验工程的想法,看起来工程的框架还是不太好。我总觉得好的框架应该是很容易修改的,现在每次想要往工程里新加一组实验就觉得有些代码碍手碍脚。如果不想有重复代码函数粒度就太小,而且接口复杂不可读,时间一长就看不出它们都是干什么的了。否则就有大段的重复代码,十分难看。如果把实验操作部分放到Bash脚本里面,移植又是一个问题。很少看到讲这种不大的工程怎么去搭框架的问题,苦于自己技术水平不够,想想真是头疼…

比较变量地址并不可靠

最近云风大牛又在黑我C++,可是在我学会之前,我还是要坚定不移地待在这贼船上。 嘿嘿 :] “用比较地址的方法来判断两个变量(的引用)是不是同一个变量是不可靠的”,这个问题很简单,却也容易忽视。 现实的情况是这样的。在写Computer Vision实验的时候,因为程序要面临的计算量往往很大,对程序的性能的优化是十分重要的。 所以我就写出了这样的代码: void foo_func(Foo& foo) { //< 如果foo和上次传入的是同一个,就省掉一部分重复计算 static Foo *p_foo = NULL; if (p_foo != &foo) { p_foo = &foo; //< 大量计算 } //< 后续计算 } 在实验里,Foo这个类本身往往比较复杂,不可能做内容的逐一比较,同时这个类的实例在初始化之后内容就保持不变。写这个函数的时候没有觉得有什么问题,结果也是正确的。 但是,这么做显然是不可靠的。 这段代码就说明问题了: #include int main(int argc, char **argv) { using namespace std; for (int i = 0; i < 100; i++) { […]

Mac远程桌面到Linux服务器

假期结束,回到学校开始干活 :] 为了远程使用Linux服务器,折腾了一个下午。最终看来还是用vnc最简单了。 实验室有两台强劲的Linux服务器用来做研究。之前我一直都是用ssh登到服务器上去码代码,反应速度很快,感觉很不错。但是因为在做机器视觉,难免需要看远程的图片。命令行虽然快,总不能每次都把图片拷贝到本地再看,有时候需要可视化中间结果,ssh也行不通。 当本地机器是Linux系统的时候比较好办。可以用ssh加X forwarding的方法。在本地开一个X,然后把远程服务器的X指令通过ssh转发到本地的X,码代码没有什么延迟,感觉还是很不错的。 sudo X :11 vt11 2>&1 >/dev/null & 这样可以在本地新开一个X,Ubuntu下用Ctrl+Alt+F11可以切到第11个虚拟终端 回到之前的终端,开ssh和xterm xterm -display :11 -e ssh -X server-host & 然后可以切换到第11个虚拟终端来使用远程Linux服务器上的X了。 这样虽然好,但是要求本地机器上有安装X。在Windows和MacOS下虽然有解决方法,但是比较麻烦。 用VNC的话就没有这个问题,毕竟VNC的客户端是很容易找的。 当然需要先ssh登录到Linux服务器上安装vncserver sudo apt-get install vnc4server 然后启动vncserver vncserver 这样就搞定了。 在本地的Mac下可以用自带的Screen Sharing App或者著名的Chicken of the VNC连接到server-host:5901来查看和控制远程Linux桌面。 在服务器上启动了vncserver之后,可以通过修改 ~/.vnc/xstartup 这个文件,来指定远程的X启动之后要执行什么命令。我喜欢用openbox,所以我的xstartup文件就是这样子 #!/bin/sh # Uncomment the following two lines for normal desktop: # unset […]

dup, pipe 和 fork

(好久没更新了,呼…一大波死线刚刚结束…) 我几乎一直在用Bash,可是却少有接触到Unix系的系统编程,对系统调用还是知之甚少。这两天实验室里讨论了一个比较基础的问题: 在自己写的程序中,怎么样得到另一个可执行文件的输出? 比如我们有/bin/pwd这个可执行文件,我们可以在自己的程序中用 system(“/bin/pwd”); 或者是 execl(“/bin/pwd”,”.”,NULL); 调用它。 如果想要得到它的输出,应该怎么做比较好? 这个其实是作业题的范畴,涉及到了几个Unix的系统调用: #include pid_t fork(void); #include int pipe(int fildes[2]); #include int dup(int fildes); int dup2(int fildes, int fildes2); 手册里有各个函数的详细解释。 在这个例子里,pipe用来生成一对文件描述子 (file descriptor,我觉得描述子这个翻译不是很好…),往第二个描述子里写内容,从第一个里面读内容。fork用来得到一个子进程,这里,我们会让子进程来执行pwd,并且把输出写到pipe的一端,然后父进程可以从另一端读入。 但是pwd默认输出到屏幕,也就是标准输出,我们需要使用dup2,把标准输出指向pipe的一端,这样就可以完成任务了。 所以,最终的代码是这样的 #include #include #include #include int main(int argc, char **argv) { int fd[2]; int pid; pipe(fd); int rpipe = fd[0]; int wpipe = fd[1]; […]

rlwrap – 命令行下readline的封装

发现了rlwrap这个好东西。 在Mac OS和Linux下一直都用bash,bash下命令的输入都是通过readline这个库来处理的。也就是说,上下箭头查看历史命令,Ctrl+r反向查找匹配历史输入,以及Ctrl+w, Ctrl+a等等操作都是由readline提供的。rlwrap提供了readline的封装! rlwrap runs the specified command, intercepting user input in order to provide readline’s line editing, persistent history and completion. 也就是说rlwrap提供一个输入环境,在这个输入环境下可以使用readline的各种功能。如果一个程序在命令行下接受输入,那么用rlwrap直接就可以得到像在bash下输入那样的效果。 比如一个简单的反转输入行的程序 #include #include #include int main(int argc, char **argv) { using namespace std; string str; cout

在latex中调整hyphenation

用latex写英文论文的时候,可能会遇到断字符 (hyphenation) 在不该断开的地方断开的问题。因为英文单词长短不一,latex排版的时候为了让论文整体上看起来比较美观,可能会把落在行尾的单词从中断开,一部分留在当前这一行并且以一个短横线(-)也就是Hyphenation结尾,剩下的部分新起一行。 在英文文章的排版中,hyphenation是很重要的,特别是当行尾的单词很长的时候,如果不作断字,把单词都放在当前行就显得挤,新起一行就显得松。因为中文文章不存在这个问题,所以自己平时也没注意到。至于各个单词具体应该怎样断字,我还没有完全弄清楚,似乎也没有一个明确的规则,而且对于美式英语,英式英语也不尽相同。但是有一些简单考量一个断字点是不是正确的方法,比如,会不会造成歧义,是不是和单词的读音一致,或者是不是前/后缀之类的。 latex使用了处理断字的算法去自动的找断字的地方,而且latex会调整单词间距,使得文章看起来不会显得疏密不一致。大多数情况下,这些算法都工作得很好。但是因为断字的算法是根据某种规则来处理单词的断字,而不是依照人工事先标注的字典,所以,它仍然会出问题。或是在不该断的地方断开了,又或者是断开的地方太多了等等。在latex下可以通过调整参数和指定断字点来处理这些问题。 \hyphenpenalty=5000 \tolerance=1000 可以把这两个参数的调整加到tex文件里。hyphenpenalty的意思比较显而易见,这个值越大断字出现的就越少。tolerance越大,换行就会越少,也就是说,latex会把本该断开放到下一行的单词,整个儿的留在当前行。调这两个值就可以得到不一样的排版,有可能可以解决断字太多的问题。 如果遇到了断开的地方不对的情况,也可以手动来指定一个单词应该怎么断。 \hyphenation{hy-phen-a-tion} 这个命令告诉latex,hyphenation只能从标有短横线(-)的地方断开。 嗯,就是这些了。

橡皮鸭调试法

偶然在StackOverflow上看到Rubber duck debugging (wiki) 这个概念,有点儿意思,不过直译成橡皮鸭调试法好像比较弱啊。 按照wiki上的说法 传说中程序大师调试代码的时候会在桌上放上一只玩具橡皮鸭,调试的时候他会不断地,详细地,向鸭子解释自己的代码… 如果没有玩具小鸭子也可以考虑向其它东西倾诉..比如桌上的花花草草,键盘鼠标 (汗)。 好吧,正经地说这也是软件工程里的一个概念,一边阐述修改代码的意图一边做调试,就会更容易发现自己的错误。 类似的,有一种现象叫做Cone of Answers,不知道如何翻译这个词。这是一个常见的现象。你的朋友跑来问你一个问题,但是当他自己把问题说完,或者说到一半的时候就想出了答案走了,留下一脸茫然的你。是的,这个时候你就起到了那只橡皮鸭子的作用… 相似的概念还有不少,前面的wiki页面底部列出了好几个。总的来说,在你试图表述自己的想法的过程中,自然地在促使自己去整理思路,重新考虑问题。Thinking out loud 可能是一种不错的做法。