李迟2011年4月知识积累
我从来不觉得写代码只是写代码的事,也不是整天拿数据结构和算法来研究,拿C、C++大头书来看。我对自己的要求是:坚持融会贯通,坚持多层次联系,坚持学习,坚持积累。
非代码知识
主要关于linux日常使用的。
1、将man转换成pdf,如
(看似有空格的地方,实际上就是有空格)
注意,像write这个函数,需要在-t 后加2,以表示它是系统函数。
2、objdump反汇编,如果编译使用-g选项,可以用-dS选项:
3、hexdump可查看很多种格式的文件,如二进制:
显示结果有3列,依次为偏移、十六进制数据,可读(可打印)字符。这与用UE打开二进制文件效果一样。
4、在代码前面添加行号:
5、shell操作
近来经常用SecureCRT操作linux,有时不太喜欢用光标那几个键移动,经常使用组合键,由于花了一定时间学习emacs(约一年前开始接触,断断续续用不少时间)。下面总结一下自己在shell(bash)中常用的快捷键,对emacs熟的人应该很清楚了,最英文比较敏感的也应该意会到每个单词约表示什么意思。
C+a:移到命令开始处
C+e:移到命令结尾
C+f C+b:向前、向后移一个字符
M+f M+b:向前、向后移一个单词
可用比较长的命令行感受一下这些命令的便捷,最经典的,假如配置qtopia2时有前面某个地方写错了,除了使用光标移到前面外,可以使用M+b向后移,更可以使用C+a直接移到开头。C+p C+n:前一历史命令、后一历史命令
C+k:删除光标至行尾所有字符。——称之为剪切更恰当
C+w:似乎与C+k一样
C+y:粘贴
C+l:清屏,与clear命令作用相同
C+u:删除整行,可用C+y粘贴
……其它的
除了emacs、bash外,在u-boot命令行中也有类似的。可研究一下readline这个库。
代码点滴
1、获取系统信息:
#include <stdlib.h>
#include <stdio.h>
#include <sys/utsname.h> /* uname */
int main(void)
{
struct utsname name;
uname(&name);
printf(“%sn%sn%sn%sn%sn”, name.sysname, name.nodename,name.release, name.version, name.machine);
return 0;
}
运行结果:
$ ./a.out
Linux
FightNow
2.6.27.25-78.2.56.fc9.i686
#1 SMP Thu Jun 18 12:47:50 EDT 2009
i686
它与uname -a作用一样。
2、函数指针测试:
/*****************************************************************
函数指针测试
$ ./a.out
in func:sig1, num:100
in func:foobar 100 200
in func:sig2, num:250
in func:foobar 300 400
in ts_input_read()
read me
2011-4
*****************************************************************/
#include <stdio.h>
/*函数指针*/
/* 这两种有何区别? */
typedef int boot_fn(int a, int b);
typedef int (*boot_fn_p)(int a, int b);int foobar(int a, int b)
{
printf(“in func:%s “, “foobar”);
printf(“%d %dn”, a, b);
return 0;
}
void sig1(int num, boot_fn handle)
{
printf(“in func:%s, num:%dn”, “sig1″, num);
handle(100,200);
//printf(“%p %pn”, handle, &handle);
}
void sig2(int num, boot_fn_p handle)
{
printf(“in func:%s, num:%dn”, “sig2″, num);
handle(300,400);
//printf(“%p %pn”, handle, &handle);
}
/*结构体中的函数指针*/
struct tslib_ops {
int (*read)(char *inf, int nr);
int (*fini)(char *inf);
};
struct tslib_module {
void *handle;
const struct tslib_ops *ops;
};
static int ts_input_read(char *inf, int nr)
{
printf(“in ts_input_read()n”);
printf(“%sn”, inf);
return 0;
}
static int ts_input_fini(char *inf)
{
printf(“int ts_input_fini()n”);
return 0;
}
static const struct tslib_ops input_ops = {
.read = ts_input_read,
.fini = ts_input_fini,
};
struct tslib_module module;
int main(void)
{
sig1(100, foobar);
sig2(250, foobar);
module.ops = &input_ops;
module.ops->read(“read me”, 11);
return 0;
}
上面代码中使用了稍微修改后的tslib中的一些代码。
3、论“断言”
网上很多笔试题都喜欢用断言,经典者莫如strcpy等等函数的实现,如无断言,则说明应试者没有具备基本的出错处理能力云云。见那么多人喜欢断言,于是用gcc和vc测试了一下。
在gcc下故意造一错误,用断言判断之:
#include <assert.h>int main(void)
{
int f = 250;
assert(f!=250);
return 0;
}
编译无警告,运行出错,如下:
a.out: test.c:7: main: Assertion `f!=250′ failed.
已放弃
说明断言生效了。
同样代码,在vc6.0下测试,除了弹出Debug Error!对话框外,dos窗口还出现:
后果非常严重:程序退出运行,而其它信息与操作系统有关。
不过,说实话,我很少用到断言。出错信息的处理每个人都不相同,但是原则都是尽可能地友好、人性化。比如,调用malloc需要判断返回值,不过我没有使用assert,只是简单打印出错信息,返回负数。
有人问我为什么要判断malloc的返回值,我回答不上来。在调用系统调用时我也判断返回值,不为什么,只是对自己写的程序负责,为了方便调试、日后管理。
但是,跟人讨论技术时,时刻将技术名词挂载嘴边,会显得自己更有水平(xx设计模式、xx算法、xx架构,等等)。至于如何交流、如何忽悠人,就仁者见仁了。
说到笔试,很多资料都有这么一题:
写一strcpy函数,让面试者说。
说什么?说参数有没有const,使用了assert没有,返回值有没有?注意不注意结束符。并写一个标准的strcpy。
其实我也想出一笔试题:
求sizeof(int)。
如果面试者直接说4,说明它在32位平台上写过程序。
如果他问面试官这题目的环境、平台,说明他注意到了不同平台会有不同结果。
如果他继续讨论单片机、ARM、x86甚至MIPS平台,说明他有一定的硬件功底;
如果他再讨论了计算机的组成及结构,冯·诺依曼体系,讲述了当初计算机的发展,说明他在计算机领域已经有一定水平。
如果再讨论到计算机科学的方方面面,并展示自己写的操作系统、编译器及科学研究成果,那么他不用面试了,可以去拿计算机领域里的大奖了。
4、
char ch = “Fuck the world!”[2];
实际上ch为字符“c”,即字符串第2个字符(从0算起)。与那个得过奖的unix程序本质一致。参见:
其它未记录的还有一些。
如果本文对阁下有帮助,不妨赞助笔者以输出更多好文章,谢谢!
本文固定链接: /my-library/code-for-april-2011.html