Learn by Making Notes.
Share by Posting Notes.

Thu, Mar 20, 2014

cygwin的默认终端使用起来有一些不顺手。之前用的puttycgy(链接)在2011年末后就不再维护了。搜索后发现一个新的(更好的)选择——mintty。mintty

  • 可以配置为鼠标右键粘贴(默认是中键粘贴,但是中键比较难按……)
  • 可以方便地通过拖拽文件或者目录的图标到mintty窗口来得到路径
  • 可以按住Ctrl点击来打开文件或者URL
  • 可以通过Ctrl+“+”和Ctrl+“-”来缩放字体
  • 可以方便地更改字体,可以选择一些对中文更友好的字体,比如“Lucida Sans Typewriter”
  • ……

###安装 通常cygwin的bin目录下已经自带了mintty程序。如果不存在也可以使用cygwin的setup.exe程序来下载/安装;可以在“Shell”分类下找到mintty。
也可以在mintty的项目网站上下载(链接)。

###其他 如果使用mintty时,提示找不到“ls”,“pwd”等命令,可以将cygwin的bin路径加入到Windows的PATH环境变量中。
关于mintty的使用说明,可以直接在mintty中查看手册man mintty,也可以查看文档(项目网站和下载的安装包中都有)。

Mintty logo

HAVE FUN.

Wed, Jan 08, 2014

expect是Unix/Linux上一个用于自动化(automating)交互程序的操作的工具。典型的交互程序有ftp,ssh,telnet等。 expect可以启动(spawn)一个交互程序,然后监听/等待(expect)它的输出;当监听到指定的输出时,再发送(send)相应的消息给这个程序。

自然地,expect可以很轻松地完成一些自动输入密码的任务,省去每次人工输入的烦恼。像bash一样,expect也有它自己的脚本语言。 下面给出一个免密码运行su(准确地说是执行su命令时让expect自动输入密码)的expect脚本。

spawn su
expect "Password:"
send "123456\r"    #发送密码,记得加上\r来模拟人类的回车动作

expect "\$ "       #su成功后开始等待终端提示符,我的终端提示符是$,这个符号需要转义(貌似
                   #我的expect有个bug,仅仅转义$并不行,必须后面跟个空格);你的root终端
                   #提示符可能是“#”等其他字符,请相应地改成 expect "# "
send "pwd\r"       #现在我们可以以root身份执行命令了;比如执行pwd命令;记得加上\r,需要有一个回车动作

expect "\$ "
send "cmd_2\r"     #以root身份执行其它命令...

expect "\$ "       #记得加上这个expect语句,要不然可能还没有看到“cmd_2”命令的输出,expect脚本就
                   #已经退出了。这个expect语句会让expect程序等待若干秒,然后再(超时)退出。

假设这个文件叫passwordless_su.expect,运行如下命令就可以自动登录切换成root并执行指定命令,

expect passwordless_su.expect

当然,假设你的expect程序位于/usr/bin/expect,也可以在这个脚本的第一行加上,

#!/usr/bin/expect

并且为这个脚本加上执行权限(chmod u+x passwordless_su.expect),然后直接执行它。

参考资料,
The Expect Home Page
Getting Started With Expect

Mon, Nov 04, 2013

C++在C风格的类型转换(Type Cast)之外,引入了4种新的类型转换操作符:dynamic_castreinterpret_caststatic_castconst_cast,它们能完成C风格类型转换相似的功能,也有C风格类型转换所不具有的能力。最近,在面试的时候被问到了dynamic_cast相关的问题,所以就借机做一下总结。

类型和转换

类型可以简单分为3种类型,基本类型(比如int,double等)、指针类型和类类型(指C++中的class,或者C中的结构体)。
对于C语言来说,程序员可以在基本类型之间、指针之间、或者基本类型和指针之间(比如指针和整数之间)进行隐式的或者显式的(强制的)转换。
对于C++语言来说,由于单参数构造函数和operator函数的存在,程序员还可以在基本类型和类类型之间做隐式的或者显式的转换。

阅读更多…

Tue, Jul 30, 2013

最近在面试的时候被问到一个算法题:

有一个升序排列的数组,经过一系列的“平移”操作,然后在平移后的数组中查找某个值;请给出一个算法。
平移的定义如下:
假设有数组{1, 2, 3, 4, 5}, 平移最后两位,那么数组变为{4, 5, 1, 2, 3}

首先,一系列平移操作可以看成是一次平移。比如,
先平移最后两位到左边,得到{4, 5, 1, 2, 3}
再平移最开始的三位到右边,得到{2, 3, 4, 5, 1}
上述两次平移操作的结果和一次平移第一位到右边的效果是相同的。

注意到数组最初是升序排列的,可以想到用二分搜索查找。经过一系列平移后,虽然整个数组不再是升序排列了,但是可以看到数组被分成了两个部分(子数组),各自都是升序的。比如,{4, 5}{1, 2, 3}。如果可以找到数组在什么位置被截开,那么就可以对两个升序子数组进行二分查找。

阅读更多…

Sun, Jul 07, 2013

昨天往github pages的repository里提交了一篇文章后,却发现github pages的页面一直没有更新——看不到新提交的文章。网上搜了一些资料,最后解决了这个问题。

一般来说,只要你的github pages repository有新的提交,github的服务器就会运行jekyll编译你的repository(延时很小)。如果编译出错,那么你的github pages页面是不会更新的;同时,github也会给你发一封提醒邮件,大致内容如下,

The page build failed with the following error:
page build failed

给出的错误信息很有限,仅仅通知你编译出错。

要找到出错的原因,首先确认下github pages服务有没有down掉;查看这个网址,https://status.github.com/,可以了解服务器的运行状态。如果服务器运行良好,那么极有可能是提交的内容有错误。 可以在本地用jekyll编译一下repository,看看是否有错误。首先,更新一下本地的jekyll。github可能使用了较新版本的jekyll,所以即使你使用以前的本地jekyll编译没有问题,远端的jekyll编译时也可能出错。(当然,最好是保证本地和远端的jekyll版本一样。但是,还没有发现查看远端jekyll版本的方法。)

$ sudo gem install jekyll
$ jekyll --version 然后,在本地编译你的repository。

$ jekyll build --safe jekyll给出的出错信息还是很详细的,能看出在什么位置发生了错误。比如,

| Maruku tells you:
+---------------------------------------------------------------------------
| Invalid char for url
| ---------------------------------------------------------------------------
| 结构如下所示,  N![ELF layout]("../images/blog/217px-elf-layout.png"
| --------------------------------------|-------------------------------------
|                                       +--- Byte 206
| Shown bytes [168 to 75] of 257:

“Maruku”应该是Markdown语法相关的错误。根据错误信息,修正相关的错误并重新提交,应该马上就可以在 github pages上看到新的提交了。(有时候即使本地有错误,也可以在本地server上看到新的改动;但是远端的服务器会要求更严格。)

所以,在提交改动前,最好保证在本地能编译无错。同时,也要时常更新本地的jekyll版本。

文章的时间

我在今天写了一篇博客,本地jekyll编译没有任何问题,但是Github Pages上却始终没有更新。 Google了一番,发现是个时区问题。Github Pages的server应该是跑在UTC时区下的,而 我所在的时区是北京时区,也就是UTC+8。在我今天发布的这篇博客里,所有的时间用的都是 UTC+8时区的本地时间。Github Pages估计只会编译server的当前时刻之前的文件。

把我的文章所用的时间都设置成前一天,再push一下,Github Pages就立马更新了。

参考链接:
https://help.github.com/articles/pages-don-t-build-unable-to-run-jekyll
http://youngsterxyf.github.io/2013/01/08/fix-github-pages-builds-failed/
http://python-china.org/topic/481

Sun, Jul 07, 2013

《The Standard C Library》(《C标准库》)中有这么一道习题,

0.2 编写一个包含下面这行代码的(正确的)程序:    
    x: ((struct x*)x)->x = x(8);   
描述x的5个不同的用途。

下面是一个答案,

#include <stdlib.h>
#include <stdio.h>

#define x(a) ((a)*(a))

struct x {
    int x;
};

int main(int argc, char **argv)
{
    void *x = malloc(sizeof(struct x)); 
    goto x;

    x: ((struct x*)x)->x = x(8); /* THE LINE */
    
    printf("%d\n", ((struct x*)x)->x);
    return 0;
}

这个程序能正确地编译、运行,其结果为64。

阅读更多…
c
...

Thu, May 16, 2013

有些时候(比如debug或者抛异常的时候),你希望得到当前函数的调用栈。使用backtrace函数和addr2line程序可以达到这一目的。backtrace是GNU提供的C标准库中的一个函数;addr2line则是GNU提供的二进制工具集Binutils中的一个程序。

int backtrace (void **buffer, int size)
The backtrace function obtains a backtrace for the current thread, as a list of pointers, and places the information into buffer.
将当前线程的调用栈信息存放在buffer数组里;size为buffer数组的大小;如果实际的调用栈的大小(层数)小于size,那么返回实际的层数,否则返回size。

addr2line
Translates addresses into file names and line numbers.
将地址信息翻译成相应的源文件名和行号。

###backtrace的实现 backtrace函数的定义在glibc库中backtrace.c文件中,是一个非常小巧的函数。

阅读更多…

Wed, May 15, 2013

我的XCode版本是4.6.2。

新建一个C++工程的步骤如下,
第一步,打开“File”->“New”->“Project…”,在弹出的选择模版的对话框中选择“OS X”->“Application”->“Command Line Tool”,如图

xcode c++ step1

第二部,填好工程名字(Product Name);在“Type”下拉列表中选择“C++”;取消选择“Use Automatic Reference Counting”(Apple应该没有为C++提供ARC的吧),如图

xcode c++ step2

完成,新的C++工程就建好了。

待做——向XCode中导入已经存在的C++工程。
http://stackoverflow.com/questions/5034286/import-existing-c-project-into-xcode-ide, Do more search.