「true」条件 (x = x ?:) に値を代入せずに、なぜ三項演算子を使用するのでしょうか。1)
-
25-09-2019 - |
質問
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/ .
解決
これは GNUとしてを許可されていますCに不明瞭拡張
省略オペランドと5.7条件文
の条件で中間オペランド 表現を省略することができます。そして、もし 最初のオペランドは、その値は、ゼロでありません 条件付きの値 表現ます。
したがって、発現
それがゼロでない場合は、x ? : y
はxの値を有します。 そうでない場合、yの値
この例では、完全に同等です
へこの単純な場合には、x ? x : y
、能力へ オミット真ん中のオペランドではありません 特に便利。とき、それはなり 最初のオペランドがない場合に便利です、 またはかもしれない(それがマクロ引数である場合)、 副作用が含まれています。そして、繰り返し 真ん中のオペランドだろう 二回の副作用を行います。 真ん中のオペランドを省略すると、使用しています 値がすでになしに計算します それを再計算の望ましくない影響ます。
あなたはおそらくこれは、読みやすさと移植性の理由のために推奨される回避、推測することができたよう。私は正直C.このような文法、互換性のない拡張機能を見て驚いています。
他のヒント
これは GCC拡張には "手段ということです条件が真の場合、それは、この他の値が「、それ以外の使用を使用するので、
machine->max_cpus = machine->max_cpus ?: 1;
の省略形です
machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;
の条件は、副作用を持っている場合、それは一度だけ実行されますが、
GCCの-pedanticフラグを使用して、それは言ってない。
のfoo.c:5:警告:ISO Cは禁止 の中期を省略?: 表現
これは GCC拡張のだし、それ条件は副作用を持っているときに、より興味深く、有用な取得します。
この場合は、はい、人はそれが何よりも不明瞭だ同意するだろう、私のために。
K&R BNFは、発現が間に必要とされることを示します "?"そして ":"。私は、gccが診断せずにいることをコンパイルする必要があるとは思わない。
これにはもう 1 つの便利なケースがあります。nil を返す可能性のある関数またはメソッドを呼び出すときに、2 回呼び出すことを避けたい中間変数を削除することです。たとえば (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条約ですが、ほとんどの現代の言語はそれを禁止し、移植努力を複雑にしています。
他の人が言ったように、それも標準以外の拡張であるため、携帯性が考慮されている場合は避けるべきです。