通过看linux环境相关源码学习编程(持续更新)

第一条:结合枚举enum声明和宏定义来定义变量:这样可以不用去定义一个enum变量(Form Memcahced)

enum
  {
    DT_UNKNOWN = 0,
# define DT_UNKNOWN	DT_UNKNOWN
    DT_FIFO = 1,
# define DT_FIFO	DT_FIFO
    DT_CHR = 2,
# define DT_CHR		DT_CHR
    DT_DIR = 4,
# define DT_DIR		DT_DIR
    DT_BLK = 6,
# define DT_BLK		DT_BLK
    DT_REG = 8,
# define DT_REG		DT_REG
    DT_LNK = 10,
# define DT_LNK		DT_LNK
    DT_SOCK = 12,
# define DT_SOCK	DT_SOCK
    DT_WHT = 14
# define DT_WHT		DT_WHT
  };

第二条:在定义结构体的时候,可以采用unsigned char格式,这样就避免字节填充(Form FastCGI)

typedef struct {
    unsigned char version;
    unsigned char type;
    unsigned char requestIdB1;
    unsigned char requestIdB0;
    unsigned char contentLengthB1;
    unsigned char contentLengthB0;
    unsigned char paddingLength;
    unsigned char reserved;
} FCGI_Header;

对于这个例子来说,本来requestID应该定义为int,为了防止字节填充所带来的内存浪费,采用上面的方式可以避免字节填充。即requestID=requestIDB1<<8+requestIDB2


第三条:当一个结构体包含的信息很多,当外部程序只需要内部的部分信息时,可以通过把该部分信息放在一个独立的结构体中,并把该小结构体放在大结构体的最前面,此时可以同一个首指针访问到两个结构体。这种信息的封装虽然不能保证信息安全,但是可以减少内部和外部程序之间耦合度和关联度(原先两个程序之间的关联是一个大结构,现在通过一个小的就可以了)(Form linux/ipc/)


大的结构体如下:

/* one msq_queue structure for each present queue on the system */
struct msg_queue {
	struct kern_ipc_perm q_perm;
	time_t q_stime;			/* last msgsnd time */
	time_t q_rtime;			/* last msgrcv time */
	time_t q_ctime;			/* last change time */
	unsigned long q_cbytes;		/* current number of bytes on queue */
	unsigned long q_qnum;		/* number of messages in queue */
	unsigned long q_qbytes;		/* max number of bytes on queue */
	pid_t q_lspid;			/* pid of last msgsnd */
	pid_t q_lrpid;			/* last receive pid */

	struct list_head q_messages;
	struct list_head q_receivers;
	struct list_head q_senders;
};
第一个小的结构体如下:

struct kern_ipc_perm
{
	spinlock_t	lock;
	int		deleted;
	int		id;
	key_t		key;
	uid_t		uid;
	gid_t		gid;
	uid_t		cuid;
	gid_t		cgid;
	umode_t		mode; 
	unsigned long	seq;
	void		*security;
};
这样就可以通过一个struct kern_ipc_perm的指针把部分信息(一个队列的基本特征信息)开放给外部程序,而struct msg_queue中list_head q_messages为真正队列内容,在有些程序只需要特征信息而不需要队列内容时候,不需要知道struct msg_queue结构。假如现在知道特征信息后,需要继续知道具体的队列内容,只需要对struct kern_ipc_perm进行转换为struct msg_queue,就可以得到具体队列内容。

第四条:利用结构体中隐性字段来存储该结构体的内容字段,利用直接字段来存储特征内容(Form linux /ipc)

struct msg_msg {	
	long  m_type;          
	int m_ts;           /* message text size */	
	/* the actual message follows immediately */
};

在上面的例子里面,该结构体是用来存储一个消息(包括特征和具体内容),但是该结构体中只有一个消息类别和消息大小的字段,没有一个字段来存储实际消息内容,其实里面是利用了一个隐性字段来存储消息内容。struct msg_msg *p+sizeof(msg_msg)+[0,p->m_ts]之间就是具体的消息内容

该技巧在写类库的时候比较好用。比如一个queue的队列,提供队列的构造,元素添加,元素删除等功能。在类库的眼中,我只关心队列中每一个元素的next字段,而不关心队列元素其他内容字段。因此在类库中定义一个节点元素和一个队列如下:

struct queue_node{
     struct queue_node *next;
 };

 struct queue{
     struct queue_node *head;
     struct queue_node *tail;
};
在用户代码中,定义一个和struct queue_node结构体格式一样的结构体:第一个元素为next字段,后面可以添加内容字段。比如

struct myNode{
     struct myNode *next;
     int data;
};
类库函数的参数为void *指针,在内部可以把该指针转化为struct queue_node类型的指针进行处理。
类库函数的对该指针进行处理以后,返回一个void *,在用户代码,可以把指针转化为我们想要的节点指针。

//类库代码
int addTail(void *node,struct queue *queue)
{
struct queue_node *qn=(struct queue_node *)node;
//用户代码
struct  myNode *node=(struct myNode *)removeHead(q);

这样在类库代码中,不需要知道用户代码中具体节点的节点内容。不知道还有没有更好方法?


第五条:利用宏定义来简化函数的编写和函数的使用,针对参数为变量,指针,指针的指针的情况   (Form php/zend.h)

具体看例子:

#define Z_REFCOUNT_PP(ppz) Z_REFCOUNT_P(*(ppz))

#define Z_REFCOUNT_P(pz)   zval_refcount_p(pz)

#define Z_REFCOUNT(z)      Z_REFCOUNT_P(&(z))


static zend_always_inline zend_uint zval_refcount_p(zval* pz) {
return pz->refcount__gc;
}




你可能感兴趣的:(编程,linux,linux)