Полностью понять операцию приращения префикса (++) - PullRequest
4 голосов
/ 28 апреля 2011

У меня есть следующий код, и я ожидаю, что вывод:

foo(0) -- 2   /* 1*2 */
foo(2) -- 12  /* 3*4 */
foo(4) -- 30  /* 5*6 */

но у меня есть

foo(2) -- 4
foo(4) -- 16
foo(6) -- 36

вместо этого. Может кто-нибудь объяснить мне, что случилось?

include <stdio.h>

int main()
{
    int counter;    /* counter for loop */

    counter = 0;

    while (counter < 5)
        printf("foo(%d) -- %d\n", counter, ((++counter)*(++counter)));

    return (0);
}

Ответы [ 4 ]

13 голосов
/ 28 апреля 2011

Как только вы используете ++ - префикс или постфикс - для переменной, вы не сможете использовать ее снова для той же переменной до следующей точки последовательности . Если вы это сделаете, поведение кода не определено - компилятору разрешено делать все, что он хочет .

Между двумя выражениями (++counter) в вашем коде нет точек последовательности, поэтому вы нарушили это правило. Вместо этого вы должны написать что-то вроде этого:

while (counter < 5) {
    printf("foo(%d) -- %d\n", counter, (counter+1) * (counter+2));
    counter += 2;
}
4 голосов
/ 28 апреля 2011

(++counter)*(++counter) на самом деле неопределенное поведение в C, так как переменная изменяется дважды без точки последовательности (то есть a ;) между ними. Результат может отличаться для разных компиляторов. Некоторые могут вместо этого отформатировать ваш жесткий диск, но, к счастью, ваш компилятор этого не сделал.

Кроме этого, мало что можно понять о приращении префикса. bar(++i) является сокращением для

i += 1;
bar(i);
0 голосов
/ 28 апреля 2011

Вы ожидаете, что это сделает

++ c = 1 * ++ c = 2

= 1 * 2 = 2

То, что на самом деле происходит, это

++ c = 2 * ++ c = 2

= 4

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

0 голосов
/ 28 апреля 2011

Приращение префикса означает, что приращение выполняется перед оставшимися операциями. Насколько мне известно, официальное требование состоит в том, что оценка счетчика ++ не является исходным значением.

Вероятно, он расширяется как шаг перед оператором, например так:

 counter = counter + 1;
 counter = counter + 1;
 printf("foo(%d) -- %d\n", counter, ((counter)*(counter)));

Что бы создать поведение, которое вы видите. Моя рекомендация состоит в том, чтобы избежать чрезмерного стресс-тестирования подобных угловых случаев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...