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~78*/
 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操作。

 

7union

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);
    }
}

 

10typedef

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        

 

 

12MAP

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);

}

这种映射表的方法应用在了lmhubtelnet功能上,实现命令和函数相对应。V4cgi函数映射表也是这种方法。

 

13SET

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)))

 

对于这个集合的理解很肤浅,留待以后遇到时在学习。

 
原创粉丝点击