Тернарный условный и оператор присваивания приоритета - PullRequest
32 голосов
/ 21 сентября 2011

Я в замешательстве по поводу прямого назначения и приоритета троичных условных операторов:

#include<stdio.h>
int main(void)
{
    int j, k;

    j = k = 0;
    (1 ? j : k) = 1; // first
    printf("%d %d\n", j, k);

    j = k = 0;
    1 ? j : k = 1; // second
    printf("%d %d\n", j, k);
    return 0;
}

Я ожидаю, что результат будет:

1 0
1 0

Но бывает так:

1 0
0 0

Плюс я получаю это предупреждение:

main.cpp: 20: предупреждение: оператор не действует

о строке, которую я прокомментировал как второй.

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

Я пробовал это с g ++ --version (Ubuntu 4.4.3-4ubuntu5) 4.4.3

Ответы [ 4 ]

20 голосов
/ 21 сентября 2011

Приоритет оператора в языке C / C ++ определяется не таблицей или числами, а грамматикой.Вот грамматика для условного оператора из C ++ 0x draft chapter 5.16 Условный оператор [expr.cond] :

conditional-expression:
    logical-or-expression
    logical-or-expression ? expression : assignment-expression

Таблица приоритетов, такая как этот , следовательно, правильный, когда вы используете назначение на левой стороне двойного столбца, а не на правой стороне.В чем причина этой асимметрии я понятия не имею.Это может быть исторической причиной: в C условный результат не был lvalue, поэтому присвоение чего-либо ему не имело смысла, и в то время разрешать принятие назначения без скобок могло бы показаться разумным.

14 голосов
/ 21 сентября 2011

Вторая строка эквивалентна:

1 ? (j) : (k = 1);

Это так же, как:

j;

Это так же, как:

;

Ключ в том, что два операнда троичного условного оператора могут быть выражениями , поэтому приоритет оператора здесь не имеет значения. Просто вторым операндом является выражение присваивания k = 1.

8 голосов
/ 21 сентября 2011
(1 ? j : k) = 1;

эквивалентно,

if(true) j = 1;
else k = 1;

И

1 ? j : k = 1;

эквивалентно,

if(true) j;  // warning: statement has no effect
else k = 1;
3 голосов
/ 21 сентября 2011

Во втором случае

1 ? j : k = 1;

оценивается как:

(1) ? (j) : (k = 1);

и, поскольку каждый оценивается как true, выражение оценивается как j, что ничего не делает.

...