在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/上编译。
答案 0 :(得分:48)
这在GNU中是permitted,是C
的一个模糊扩展5.7具有省略操作数的条件
条件中的中间操作数 表达式可以省略。然后,如果 第一个操作数非零,其值为 有条件的价值 表达
因此,表达式
如果非零,则x ? : y
的值为x; 否则,y的值。
这个例子非常等效 到
x ? x : y
在这个简单的情况下,能力 省略中间操作数不是 特别有用。当它变成 有用的是当第一个操作数时, 或者可能(如果它是一个宏参数), 含有副作用。然后重复 中间的操作数会 两次执行副作用。 省略中间操作数使用 已经计算过的值没有 重新计算它的不良后果。
正如您可能猜到的那样,出于可读性和可移植性的原因,建议不要这样做。老实说,我很惊讶地看到这种语法不兼容的扩展C.
答案 1 :(得分:10)
这是GCC extension,表示“如果条件为真,请使用它,否则使用其他值”,所以
machine->max_cpus = machine->max_cpus ?: 1;
是
的简写machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;
虽然如果条件有副作用,它只会运行一次
答案 2 :(得分:6)
使用gcc的-pedantic标志,它确实说
foo.c:5:警告:ISO C禁止 省略?的中期: 表达
答案 3 :(得分:3)
这是GCC extension,当条件有副作用时,它会变得更有趣和有用。
在这种情况下,是的,我会认为它比其他任何东西都更加模糊。
答案 4 :(得分:1)
K& R BNF显示“?”之间需要表达式和“:”。我不认为gcc应该在没有诊断的情况下进行编译。
答案 5 :(得分:0)
还有另一个有用的例子 - 在调用可能返回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 @[];
}
因此,我发现它具有相当可读的有用的语法糖。缺点是
将指针隐式转换为bool。这是一个长期存在的C. 惯例,但大多数现代语言不允许它,复杂化 任何移植工作。
正如其他人所说,它也是一个非标准的扩展,所以它应该 如果可移植性是一个考虑因素,则应避免使用。
答案 6 :(得分:0)
我认为其他答案没有回答标题中的问题,并且也考虑了标签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");
}