Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

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

$
0
0
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 原文链接
阅读:29 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>