「true」条件 (x = x ?:) に値を代入せずに、なぜ三項演算子を使用するのでしょうか。1)

StackOverflow https://stackoverflow.com/questions/2806255

質問

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条約ですが、ほとんどの現代の言語はそれを禁止し、移植努力を複雑にしています。

  • 他の人が言ったように、それも標準以外の拡張であるため、携帯性が考慮されている場合は避けるべきです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top