لماذا تستخدم المشغل الثلاثية دون تعيين قيمة للحالة "الحقيقية" (x = x؟: 1)

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

سؤال

في رمز QEMU مفتوح المصدر Android ، قمت بتشغيل هذا السطر من الكود:

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/ryitout/ .

هل كانت مفيدة؟

المحلول

هذا هو مباح في 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 ، فإنه يقول

foo.c: 5: تحذير: ISO C يحظر حذف المصطلح الأوسط A ؟: التعبير

انه امتداد GCC, ، ويصبح أكثر إثارة للاهتمام وفائدة عندما يكون للحالة آثار جانبية.

في هذه الحالة ، نعم ، أنا أوافق على أنه غامض أكثر من أي شيء آخر.

يُظهر K&R BNF تعبيرًا مطلوبًا بين "؟" و ":". لا أعتقد أنه يجب أن تقوم GCC بتجميع ذلك بدون تشخيص.

هناك حالة أخرى مفيدة لهذا - القضاء على المتغيرات الوسيطة عند استدعاء وظيفة أو طريقة قد تعود إلى لا شيء ، والتي نود تجنب الاتصال مرتين. على سبيل المثال (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 طويلة الأمد ، لكن معظم اللغات الحديثة لا تسمح لها ، مما يعقد أي جهود للنقل.

  • كما قال آخرون ، إنه أيضًا امتداد غير قياسي ، لذلك يجب تجنبه إذا كانت قابلية النقل بمثابة اعتبار على الإطلاق.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top