C语言-结构体的3种用途

来源:互联网 发布:终结者2网络连接失败 编辑:程序博客网 时间:2024/06/07 01:36

C语言-结构体的3种用途

返回脚本百事通
1.通过结构体, 从函数中返回多个数据元素
例1:
/* 函数同时返回包含秒和微秒的时间差 */
typedef struct {int tv_sec;int tv_usec;} timeval;static timeval difftv(timeval a, timeval b){static timeval diff;diff.tv_sec = b.tv_sec - a.tv_sec;if ((diff.tv_usec = b.tv_usec - a.tv_usec) < 0) {diff.tv_sec--;diff.tv_usec += 1000000;}return diff;}



2.结构体可以映射数据的组织方式
例1.
/*fxp_cb_nop表示了Intel EtherExpress网卡的一个控制块*/struct fxp_cb_nop {void *fill[2];volatile u_int16_t cb_status;volatile u_int16_t cb_command;volatile u_int32_t link_addr;};
volatile 修饰符用来表明底层的内存字段将被程序之外的实体(上例为网卡)使用, 从而禁止编译器对其进行移除冗余引用之类的优化.

例2.结构体中使用bit-field语法定义只占几个bit的成员:

/* 使用位域(bit-field)来划分出精确的bit区域, 以保存指定设备上的特定数据 */typedef struct {unsigned int one:1;unsigned int two:3;unsigned int three:10;unsigned int four:5;unsigned int :2;unsigned int five:8;unsigned int six:8;} demo_type;int main(void){demo_type s = { 1, 5, 513, 17, 129, 0x81 };printf("sizeof demo_type = %u\n", sizeof(demo_type));printf("values: s=%u,%u,%u,%u,%u,%u\n",s.one, s.two, s.three, s.four, s.five, s.six);return 0;}


例3.
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;};
用来传递数据的byte_count占据了6bit的空间, 而数据的接收者和传送者的FIFO队列限制在硬件设备上分别占据了4bit和3bit的空间. 那个':2'和':1'是未命名的bit-field, 即使不写未命名的bit-field, 编译器也可能在两个成员之间插入填充位. 这样使访问效率提高.

例4:
/* TCP报文的经典定义 */struct tcphdr {u_int16_t th_sport; /* source port */u_int16_t th_dport; /* destination port */tcp_seq th_seq; /* sequence number */tcp_seq th_ack; /* acknowledgement number */[...]};



3.以面向对象的方式编程
通过结构体将相关数据和函数指针封装在一起, 来模拟类的字段和方法, 从而创建类似对象的实体.
例1:
/* 结构体domain用来表示网络协议(Internet, SNA, IPX)中的不同的域* 它封装了与特定域相关的数据(比如域所属的家族dom_family)和* 操作这些数据的方法(比如路由表的初始化方法) */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 */};该结构体类型的变量或指针(更常见)在完成初始化以后, 就可以像C++或Java对象那样使用了.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;[...]}



例2:
/* 因为同一类型的对象共享了相同的方法(函数指向了相同的函数地址)* 所以, "对象"通常只存储一个指向另一结构体的指针,* 由这个结构体负责存储指向实际方法的指针,* 从而达到在不同对象之间共享方法指针的目的 */struct file {[...]short f_type; /* descriptor type */short f_count; /* reference count */short f_msgcount; /* reference from message quene */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 */}


作者:byguess 发表于2013-4-22 12:12:17 原文链接
原创粉丝点击