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

发布于 2024-08-31 15:35:30 字数 527 浏览 5 评论 0原文

在 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 一起编译并正常工作,但不能在 http://www.comeaucomputing.com/tryitout/ 上编译。

In the Android open-source qemu code I ran across this line of code:

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

Is this just a confusing way of saying:

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

If so, wouldn't it be clearer as:

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

Interestingly, this compiles and works fine with gcc, but doesn't compile on http://www.comeaucomputing.com/tryitout/ .

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

梨涡少年 2024-09-07 15:35:30

这是 GNU 中允许的模糊扩展至 C

5.7 省略操作数的条件

条件中的中间操作数
表达式可以省略。那么如果
第一个操作数非零,其值为
条件的值
表达。

因此,表达式

<前><代码> x ? : 是

如果 x 非零,则

具有 x 的值;
否则为 y 的值。

这个例子是完全等价的

<前><代码> x ? x : y

在这个简单的例子中,能够
省略中间操作数不是
特别有用。当它变成
有用的是当第一个操作数出现时,
或者可以(如果它是宏参数),
含有副作用。然后重复
中间的操作数将
执行两次副作用。
省略中间操作数使用
已经计算出的值,无需
重新计算它会产生不良影响。

正如您可能猜到的那样,出于可读性和可移植性的原因,建议避免这种情况。老实说,我很惊讶看到这样一个语法不兼容的 C 扩展。

This is permitted in GNU as an obscure extension to C

5.7 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.

As you can probably guess, avoiding this is recommended for readability and portability reasons. I'm honestly surprised to see such a grammar-incompatible extension to C.

や三分注定 2024-09-07 15:35:30

这是一个 GCC 扩展,意思是“如果条件为 true,使用它,否则使用其他值”,so

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

是简写,

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

尽管如果条件有副作用,则只会运行一次

This is a GCC extension that means "if the condition is true, use it, else use this other value", so

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

is shorthand for

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

although if the conditional has side-effects, it will only be run once

画▽骨i 2024-09-07 15:35:30

使用 gcc 的 -pedantic 标志,它确实说

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

Using gcc's -pedantic flag, it does say

foo.c:5: warning: ISO C forbids
omitting the middle term of a ?:
expression

怪我闹别瞎闹 2024-09-07 15:35:30

这是一个 GCC 扩展,而且它变得更有趣当病情有副作用时很有用。

在这种情况下,是的,我个人认为它比其他任何事情都更晦涩难懂。

It's a GCC extension, and it gets more interesting and useful when the condition has side effects.

In this case, yes, I for one would agree it's obscure more than anything else.

临走之时 2024-09-07 15:35:30

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

The K&R BNF shows an expression is required between "?" and ":". I don't think gcc should be compiling that without a diagnostic.

ゞ记忆︶ㄣ 2024-09-07 15:35:30

还有另一个有用的例子——在调用可能返回 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
    惯例,但大多数现代语言不允许这样做,这使情况变得复杂
    任何移植工作。

  • 正如其他人所说,它也是一个非标准扩展,所以它应该
    如果完全考虑可移植性,则应避免。

There's another useful case for this -- the elimination of intermediate variables when calling a function or method that might return nil, that we wish to avoid calling twice. For example (Objective-C), suppose we want to unpack a file into an array if it exists, otherwise return an empty array.

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

The alternatives are less concise.

- (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;
}

Or uglier with multiple returns etc.

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

So it's useful syntactic sugar that I find fairly readable. The downsides are

  • Implicit conversion of a pointer to a bool. This is a long-standing C
    convention, but most modern languages disallow it, complicating
    any porting efforts.

  • As others have said it's also a non-standard extension, so it should
    be avoided if portability is a consideration at all.

伊面 2024-09-07 15:35:30

我觉得其他答案没有回答标题中的问题,并且还考虑了标签 c 。因此我添加另一个答案。

我使用这种语法来防止我的代码因 if 语句而变得丑陋。

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");
}

I feel the other answers do not answer the question in the title and also taking the tag c into account. Therefore I add another answer.

I use this syntax to prevent my code from getting ugly through if-statements.

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");

You can see the actual function call right in the beginning of the line. Compared it to the versions below, where the leading if obstructs the direct view of the function call.

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");

or even harder to read:

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");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文