reading code skill
来源:互联网 发布:找正规网络兼职 编辑:程序博客网 时间:2024/04/27 19:51
最近阅读了Code reading 《代码阅读方法与实践》看了前几章,后边是些高级应用,留待以后研究。
1)#define new(type) (type *) calloc(sizeof(type), 1)
[...]
node = new(struct codeword_entry);
学学宏定义的多巧妙
2)
In modern C and C++ programs you can often identify arguments passed by reference for efficiency purposes because they are identified by a const declarator.[6]
[6] netbsdsrc/bin/stty/print.c:56
static char *ccval (const struct cchar *, int);
为了提高效率,同时为了保证参数不被修改,用const 加传址调用。
3)
char *inet_ntoa(struct in_addr ad)
{
unsigned long int s_ad;
int a, b, c, d;
static char addr[20];
s_ad = ad.s_addr;
d = s_ad % 256;
s_ad /= 256;
c = s_ad % 256;
s_ad /= 256;
b = s_ad % 256;
a = s_ad / 256;
sprintf(addr, "%d.%d.%d.%d", a, b, c, d);
return addr;
}
在函数内部定义成static变量,函数返回这个地址后,此地址不会被释放,所以不会丢失,但是程序必须保证在下次调用这个函数前必须把addr中的数据移走,否则其中的内容将会被改变。
4)函数指针传递
void
getfile(void (*fill)(char *, long), (*skip)(char *, long))
{
[...]
(*fill)((char *)buf, (long)(size > TP_BSIZE ?
fssize : (curblk - 1) * TP_BSIZE + size));
[...]
(*skip)(clearedbuf, (long)(size > TP_BSIZE ?
TP_BSIZE : size));
[...]
(*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
[...]
}
函数指针作为函数参数是个比较高级而且灵活的应用。根据传入函数指针的不同实现对文件不同的操作。
5)问题:位段结构
In certain cases a bit field may be declared to specify a precise range of bits used to hold a particular value on the given device.[32]
[32] netbsdsrc/sys/dev/pci/if_fxpreg.h:116–125
struct fxp_cb_config {
[...]
volatile u_int8_t byte_count:6,
:2;
volatile u_int8_t rx_fifo_limit:4,
tx_fifo_limit:3,
:1;
struct RPR_ATD_TLV_HEADER
{
ULONG res1:6;
ULONG type:10;
ULONG res1:6;
ULONG length:10;
};
位段结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构比按位运算符更加方便。
位结构定义的一般形式为:
struct位结构名{
数据类型 变量名: 整型常数;
数据类型 变量名: 整型常数;
} 位结构变量;
其中: 整型常数必须是非负的整数, 范围是0~15, 表示二进制位的个数, 即表示有多少位。
变量名是选择项, 可以不命名, 这样规定是为了排列需要。
例如: 下面定义了一个位结构。
struct{
unsigned incon: 8; /*incon占用低字节的0~7共8位*/
unsigned txcolor: 4;/*txcolor占用高字节的0~3位共4位*/
unsigned bgcolor: 3;/*bgcolor占用高字节的4~6位共3位*/
unsigned blink: 1; /*blink占用高字节的第7位*/
}ch;
位结构成员的访问与结构成员的访问相同。
例如: 访问上例位结构中的bgcolor成员可写成:
ch.bgcolor
位结构成员可以与其它结构成员一起使用。 按位访问与设置,方便&节省
例如:
struct info{
char name[8];
int age;
struct addr address;
float pay;
unsigned state: 1;
unsigned pay: 1;
}workers;'
上例的结构定义了关于一个工从的信息。其中有两个位结构成员, 每个位结构成员只有一位, 因此只占一个字节但保存了两个信息, 该字节中第一位表示工人的状态, 第二位表示工资是否已发放。由此可见使用位结构可以节省存贮空间。
注意不要超过值限制
6)编写面向对象c程序
struct domain {
int dom_family; /* AF_xxx */
char *dom_name;
void (*dom_init)(void); /* initialize domain data structures */
[...]
int (*dom_rtattach)(void **, int);
/* initialize routing table */
int dom_rtoffset; /* an arg to rtattach, in bits */
int dom_maxrtkey; /* for routing layer */
}
用函数指针模拟方法,但是这些结构都需要初始化。编写代码也想写面向对象程序一样调用,理解起来很符合人的思想。
for (dom = domains; dom; dom = dom->dom_next)
if (dom->dom_family == i && dom->dom_rtattach) {
dom->dom_rtattach((void **)&nep->ne_rtable[i],
dom->dom_rtoffset);
break;
struct file {
[...]
short f_type; /* descriptor type */
short f_count; /* reference count */
short f_msgcount; /* references from message queue */
struct ucred *f_cred; /* credentials associated with descriptor */
struct fileops {
int (*fo_read)(struct file *fp, struct uio *uio,
struct ucred *cred);
int (*fo_write)(struct file *fp, struct uio *uio,
struct ucred *cred);
int (*fo_ioctl)(struct file *fp, u_long com,
caddr_t data, struct proc *p);
int (*fo_poll)(struct file *fp, int events,
struct proc *p);
int (*fo_close)(struct file *fp, struct proc *p);
} *f_ops;
off_t f_offset;
caddr_t f_data; /* vnode or socket */
};
用fileops指针实现函数共享方法。不同实体可以指向不同的fileops操作。
7)union
union overhead {
union overhead *ov_next; /* when free */
struct {
u_char ovu_magic; /* magic number */
u_char ovu_index; /* bucket # */
#ifdef RCHECK
u_short ovu_rmagic; /* range magic number */
u_long ovu_size; /* actual block size */
#endif
} ovu;
#define ov_magic ovu.ovu_magic
#define ov_index ovu.ovu_index
#define ov_rmagic ovu.ovu_rmagic
#define ov_size ovu.ovu_size
};
定义联合是需要两个值不可能同时发生,这样可以节省空间。注意到宏定义,这样方法可以方便的直接访问联合中结构的成员,不用反复写结构名了。如:
op->ov_index = bucket;
8)但更多的时候union不是为了节省空间,而是为了用一个对象存储多种不同的数据类型,一般都是在union中用enum表示不同类型。
enum msg_type {
CALL=0,
REPLY=1
};
[...]
struct rpc_msg {
u_int32_t rm_xid;
enum msg_type rm_direction;
union {
struct call_body RM_cmb;
struct reply_body RM_rmb;
}ru;
};
9)
union record {
char charptr[RECORDSIZE];
struct header {
char name[NAMSIZ];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char linkflag;
char linkname[NAMSIZ];
char magic[8];
char uname[TUNMLEN];
char gname[TGNMLEN];
char devmajor[8];
char devminor[8];
} header;
};
这个方法我应该熟悉,这是利用联合代表便宜,访问同地址数据,但是使用时需要注意,最好以字节为单位,因为如果以long,或者int为单位,有可能高地位颠倒,这是我花了好长时间自己发现的。J
下面是一个访问整数内部位置的应用。
double
frexp(double value, int *eptr) <-- a
{
union {
double v; <-- b
<-- c
struct {
u_int u_mant2 : 32; <-- d
u_int u_mant1 : 20;
u_int u_exp : 11; <-- e
u_int u_sign : 1;
} s;
} u;
if (value) {
u.v = value; <-- f
*eptr = u.s.u_exp - 1022; <-- g
u.s.u_exp = 1022; <-- h
return(u.v); <-- i
} else {
*eptr = 0;
return((double)0);
}
}
10)typedef
typedef char ut_line_t[UT_LINESIZE];
However, decrypting such declarations is not too difficult. Consider typedef to be a storage class specifier like extern or static, and read the declaration as a variable definition.
static char ut_line_t[UT_LINESIZE];
The name of the variable being defined (ut_line_t in the case above) is the type's name; the variable's type is the type corresponding to that name.
用这个方法就会破解teypdef复杂的类型定义了:
把typedef想象成static,然后变量的名字就是类型的名,变量所对应的类型就是typedef定义的类型。
11)
rknots = xalloc(MAXORD * numKnots * sizeof(rknots[0][0]));.
ddFLOAT (*rknots)[MAXORD]=0; /* reciprocal of knot diff */
PclFontMapRec ** index; <-- a
[...]
index = (PclFontMapRec **)xalloc(sizeof(PclFontMapRec *)*nindex_row); <-- b
[...]
for (i=0; i<nindex_row; i++) { <-- c
index[i] = (PclFontMapRec *)xalloc(sizeof(PclFontMapRec)*nindex_col);
[...]
for (j=0; j<=nindex_col; j++)
index[i][j].fid = 0x0; <-- d
}
对于二维数组的访问可以定义个宏,方便通用。
#define DATA( n, i, j ) ( float * ) ( *data + ( i * n ) ) + j
12)MAP
static struct key {
char *name; <-- a
void (*f)(struct info *); <-- b
[...]
} keys[] = {
<-- c
{ "all", f_all, 0 },
{ "cbreak", f_cbreak, F_OFFOK },
[...]
{ "tty", f_tty, 0 },
};
[...]
int
ksearch(char ***argvp, struct info *ip)
{
char *name;
struct key *kp, tmp;
name = **argvp;
[...]
tmp.name = name;
if (!(kp = (struct key *)bsearch(&tmp, keys, <-- d
sizeof(keys)/sizeof(struct key), sizeof(struct key), c_key)))
return (0);
[...]
kp->f(ip); <-- e
return (1);
}
这种映射表的方法应用在了lmhub中telnet功能上,实现命令和函数相对应。V4的cgi函数映射表也是这种方法。
13)SET
pbitvec[j/BITS_PER_LONG] |= ((unsigned long)1 << (j % BITS_PER_LONG));
上面是把j放入一个集合pbitvec中。先是整除,然后是取余,并进行标记。
用&可以判断j是否在一个集合中:
#define FD_ISSET(n, p) /
((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
从集合中去除一个元素:
#define FD_CLR(n, p) /
((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
对于这个集合的理解很肤浅,留待以后遇到时在学习。
- reading code skill
- Code Reading
- 【skill】push code with github
- code-reading skills
- Lua code reading
- 《Code Reading》读书笔记
- cJSON source code reading
- www.tutorialspoint.com//code reading & reading
- skill
- skill
- skill
- Skill
- 《Code Reading》一本好书
- BeansDB Source Code Reading (1)
- BeansDB Source Code Reading (2)
- Maxent Source code reading experience
- CRF++ Source code reading experience
- feeling in sourse code reading
- CISVC.EXE的资源占用
- 在Asp.Net中,导入Excel表格数据,通常有两种方法
- 二叉树的线索化
- mysql的select语句
- 求排列
- reading code skill
- 自己第一次用html
- 银行家算法
- jsp 内嵌网页内容---iframe
- 各种系统服务
- 边读代码边查书边加注释与x264命令行翻译
- 电话营销系列教程
- VC++与汇编语言混合编程事例-----冒泡排序:
- 启动和关闭外部程序