【转】三目运算符“?:”省略中间操作数的分析

/*
* Author: Godbach
* Blog:http://blog.chinaunix.net/u/33048/index.html
* 本文欢迎自由转载,但请标明出处,并保证本文的完整性。
*/
   内核代码sch_fifo.c中函数fifo_init的代码如下:

static int fifo_init(struct Qdisc *sch, struct rtattr *opt)
{
    struct fifo_sched_data *q = qdisc_priv(sch);

    if (opt == NULL) {
        u32 limit = sch->dev->tx_queue_len ? : 1;

        if (sch->ops == &bfifo_qdisc_ops)
             limit *= sch->dev->mtu;

         q->limit = limit;
    } else {
        struct tc_fifo_qopt *ctl = RTA_DATA(opt);

        if (RTA_PAYLOAD(opt) < sizeof(*ctl))
            return -EINVAL;

         q->limit = ctl->limit;
    }

    return 0;
}


其中加粗的一行代码:

u32 limit = sch->dev->tx_queue_len ? : 1;


这里发现使用了三目运算符,但是又省略的中间的操作数。这是什么用法呢?网上发帖问了别的朋友,得到链接http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc/Conditionals.html#Conditionals上介绍少,内容如下:

Conditionals with Omitted Operands

The middle operand in a conditional expression may be omitted. Then if the first operand is nonzero, its value is the value of the conditional expression.

Therefore, the expression

x ? : y

has the value of x if that is nonzero; otherwise, the value of y.

This example is perfectly equivalent to

x ? x : y

In this simple case, the ability to omit the middle operand is not especially useful. When it becomes useful is when the first operand does, or may (if it is a macro argument), contain a side effect. Then repeating the operand in the middle would perform the side effect twice. Omitting the middle operand uses the value already computed without the undesirable effects of recomputing it.

A side effect is a result of an operator, expression, statement, or function that persists even after the operator, expression, statement, or function has finished being evaluated.
原来 x ? : y 就是 x ? x : y。
   但是,通常情况下用 x ? : y 替换x ? x : y看起来并不是很友好,至少我看着觉得有些别扭。根据上面的分析,在某些情况下,在表达式x为宏定义的时候,使用x ? : y 代替x ? x : y,可以避免有些宏定义产生的边界效应。请看下面的实例代码:

#include <stdio.h>

#define INC(x) (++x)

int main(int argc, char *argv[])
{
    int x = 0;
    int y = 0;

     y = INC(x) ? INC(x) : 3;
    printf("y=%d\n", y);

     x = 0;
     y = INC(x) ? : 3;
    printf("y=%d\n", y);

    return 0;
}


该程序执行的结果如下:
[root@localhost tmp]# ./a.out
y=2
y=1

从这个结果可以看出来,表达式y = INC(x) ? INC(x) : 3中宏INC(x)进行了两次扩展。因此,导致x被计算了两次,最终结果为2。而表达式y = INC(x) ? : 3仅对宏INC(x)进行了一次扩展,因此,最终的结果为1。

这也就是“?:”省略中间操作数的用途。当然,如果像表达式
u32 limit = sch->dev->tx_queue_len ? : 1中第1个操作数表达方法比较长时
,而又想当期不为0时就取本身的值,也可以使用这种方式,节省了代码的长度。
posted @ 2011-03-23 11:04  dc0453  阅读(483)  评论(0编辑  收藏  举报