Тернарный оператор в условном цикле: порядок вычисления / оп. неясен приоритет - PullRequest
0 голосов
/ 10 января 2019

Редактировать:

Что такое реальные группы выражения «3 <8? (9 <6? 7: 5): 2> 0? 4: 1 », а что означает неассоциативный в PHP?

был предложен как дубликат, но это касается PHP, а не C.

При создании тестовых примеров для небольшой программы я внес ошибку в условная часть цикла for, например:

for(int row = 0; row < (mode == TEST) ? NO_OF_TESTS : ROWS; row++){}

(я знаю, что нужно вытащить это из цикла for, но это не меняет проблему.)

Это приводит к ошибке сегментации, запуская конец массива как выше приводит к бесконечному циклу.

Конечно, исправить было достаточно просто:

for(row = 0; row < ((mode == TEST) ? NO_OF_TESTS : ROWS); row++)
//                 ^                                   ^

Но меня больше интересует, как ведет себя ошибочная реализация.

Вот полный кусок кода (сам по себе не имеет смысла, так как вырвано из контекста, но это демонстрирует проблему).

#include <stdio.h>
#include <stdlib.h>

#define TEST 0
#define INTERACTIVE 1

#define ROWS 2
#define NO_OF_TESTS 3
#define MAX_FRUIT_LEN 50

int main(void)
{
    char test_cases[NO_OF_TESTS][MAX_FRUIT_LEN] =
    {{"Orange"},
     {"Apple"},
     {"Pineapple"}};

    int mode = TEST;
    int row = 0;

    //This fails - but in a strange way
    //Uncomment this `for` loop and comment the other one to see the effects

    //for(int row = 0; row < (mode == TEST) ? NO_OF_TESTS : ROWS; row++)

    //With the parantheses, obviously, it works.
    for(row = 0; row < ((mode == TEST) ? NO_OF_TESTS : ROWS); row++)
    {
        printf("Working:\tIn row %d: Mode: %d condition_eval: %d\n"
        , row , mode, row < ((mode == TEST) ? NO_OF_TESTS : ROWS));

        printf("Not Working:\tIn row %d: Mode: %d condition_eval: %d\n"
        , row, mode, row < (mode == TEST) ? NO_OF_TESTS : ROWS);

        printf("Row: %d \tFruit Name: %s\n",row, test_cases[row]);
    }
    printf("\nTerminating conditional evaluation (at row %d):\n", row);

    printf("Working:\tIn row %d: Mode: %d condition_eval: %d\n"
    , row , mode, row < ((mode == TEST) ? NO_OF_TESTS : ROWS));

    printf("Not Working:\tIn row %d: Mode: %d condition_eval: %d\n"
    , row, mode, row < (mode == TEST) ? NO_OF_TESTS : ROWS);

    return 0;
}

Глядя на вывод и (неправильное) условное

row < (mode == TEST) ? NO_OF_TESTS : ROWS

похоже, что компилятор интерпретирует это как:

   (row < (mode == TEST)) ? NO_OF_TESTS : ROWS
// ^                    ^

Вопрос: почему?

Это выражение:

(mode == TEST)

можно интерпретировать как правильный операнд оператора < или как левый операнд оператору ?. (Но не оба одновременно, я думаю.)

Какие правила применяются? Это вопрос приоритета оператора? Точки последовательности играют роль? Каков порядок оценки и почему?

Я совсем запутался; любая помощь очень ценится.

Ответы [ 3 ]

0 голосов
/ 10 января 2019

Тернарный условный оператор имеет низкий приоритет.

Так

row < (mode == TEST) ? NO_OF_TESTS : ROWS

сгруппирован как

(row < (mode == TEST)) ? NO_OF_TESTS : ROWS

Люди любят думать в терминах таблиц приоритетов операторов , но на самом деле группировки встроены в грамматику языка.

0 голосов
/ 10 января 2019

Да, это вопрос приоритета - реляционные операторы (а также побитовые, логические, арифметические, унарные и постфиксные операторы) имеют более высокий приоритет, чем троичный оператор, поэтому выражение a < b ? c : d анализируется как (a < b) ? c : d .

То же самое, если крайнее левое выражение равно a && b, a == b, a * b и т. Д.

0 голосов
/ 10 января 2019

Вопрос: почему?

Это вопрос приоритета оператора?

да!

Приоритет троичного оператора довольно опасен , вы не первый, кто совершает эту ошибку, я сделал сам

Лучший способ быть спокойным в выражениях - добавить ()

...