代码之家  ›  专栏  ›  技术社区  ›  RickNotFred

为什么使用三元运算符而不为“真”条件赋值(x=x?:1)

  •  38
  • RickNotFred  · 技术社区  · 16 年前

    在Android开源qemu代码中,我遇到了以下代码行:

    machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
    

    if (machine->max_cpus) {
       ; //do nothing
    } else {
     machine->max_cpus = 1;
    }
    

    如果是这样的话,是不是更清楚了:

    if (machine->max_cpus == 0) machine->max_cpus = 1;
    

    有趣的是,这种方法可以很好地编译gcc,但不能在gcc上编译 http://www.comeaucomputing.com/tryitout/ .

    6 回复  |  直到 12 年前
        1
  •  51
  •   Uri    16 年前

    这是 permitted

    5.7省略操作数的条件

    条件函数中的中间操作数 第一个操作数为非零,其值为 条件的值 表情。

     x ? : y
    

    如果x的值不为零,则为x;

    这个例子是完全等价的 到

     x ? x : y
    

    省略中间操作数不是 特别有用。当它变成 包含副作用。然后重复 中间的操作数 做两次副作用。 省略中间操作数将使用 值已在没有 重新计算的不良影响。

        2
  •  10
  •   Michael Mrozek    16 年前

    这是一个 GCC extension

    machine->max_cpus = machine->max_cpus ?: 1;
    

    是的缩写

    machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;
    

        3
  •  6
  •   Larry Engholm    16 年前

    使用gcc的-迂腐的旗帜,它确实说

    foo.c:5:警告:ISO c禁止 省略?的中间项: 表达

        4
  •  3
  •   John Marshall    16 年前

    GCC extension ,当这种情况有副作用时,它会变得更加有趣和有用。

    在这种情况下,是的,就我个人而言,我同意它比其他任何东西都更晦涩难懂。

        5
  •  1
  •   Larry Engholm    16 年前

    K&R BNF表示“?”和“:”之间需要一个表达式。我认为gcc不应该在没有诊断的情况下编译它。

        6
  •  0
  •   David Gish    10 年前

    这方面还有另一个有用的例子——在调用可能返回nil的函数或方法时消除中间变量,我们希望避免调用两次。例如(Objective-C),假设我们想要将一个文件解压到一个数组中(如果它存在),否则返回一个空数组。

    - (NSArray*)hydrateBacklogFromFile:(NSString *path)
    {
        NSArray *backlog = @[];
        NSData *backlogData = [NSData dataWithContentsOfFile:path];
        if (backlogData)
        {
            backlog = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData] ?: backlog;
        }
        return backlog;
    }
    

    备选方案不那么简洁。

    - (NSArray*)hydrateBacklogFromFile:(NSString *path)
    {
        NSArray *backlog = @[];
        NSData *backlogData = [NSData dataWithContentsOfFile:path];
        if (backlogData)
        {
            NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
            if (tempArray != nil)
            {
                backlog = tempArray;
            }
        }
        return backlog;
    }
    

    或者更丑,有多重回报等。

    - (NSArray*)hydrateBacklogFromFile:(NSString *path)
    {
        NSData *backlogData = [NSData dataWithContentsOfFile:path];
        if (backlogData)
        {
            NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
            if (tempArray != nil)
            {
                return tempArray;
            }
        }
        return @[];
    }
    

    • 指向布尔的指针的隐式转换。这是一个由来已久的C 但大多数现代语言都不允许这样做,这就复杂了 任何移植工作。

    • 如果可移植性是一个考虑因素的话,就应该避免。

        7
  •  0
  •   DarkTrick    6 年前

    我觉得其他的答案并没有回答题目中的问题,也带着标签 c 考虑到。因此,我补充另一个答案。

    foo(1) == TRUE ?: error_quit("foo(1) failed");
    foo(2) == TRUE ?: error_quit("foo(2) failed");
    foo(3) == TRUE ?: error_quit("foo(3) failed");
    foo(4) == TRUE ?: error_quit("foo(4) failed");
    

    您可以在行首看到实际的函数调用。将其与下面的版本进行比较,其中 if

    if (foo(1) == FALSE) error_quit("foo(1)" failed");
    if (foo(2) == FALSE) error_quit("foo(2)" failed");
    if (foo(3) == FALSE) error_quit("foo(3)" failed");    
    if (foo(4) == FALSE) error_quit("foo(4)" failed");
    

    或者更难阅读:

    if (foo(1) == FALSE){
      error_quit("foo(1)" failed");
    }
    
    if (foo(2) == FALSE){
      error_quit("foo(2)" failed");
    }
    
    if (foo(3) == FALSE){
      error_quit("foo(3)" failed");
    }
    
    if (foo(4) == FALSE){
      error_quit("foo(4)" failed");
    }