Сегодня мы узнаем, как НЕ надо писать программы. И - почему.
Любой начинающий (быдло)кодер знает, что писать
x-- - --x;нельзя. Но мало кто знает, ПОЧЕМУ, и что в действительности происходит. А знать это необходимо, потому как IRL всё не так просто, как в этом, далеко не тривиальном примере с тройным дном.
Итак преступим:
Как всем хорошо известно, компилятор строит для любого выражение дерево, узлами которого служат арифметические (и проч.) операции, а листьями - переменные и числа. Затем (на этапе исполнения), компилятор обходит дерево в строго определённо порядке, и выдаёт вполне детерминированный результат. При этом, следует учитывать, что константные выражения компилятор вычисляет ещё на этапе компиляции, и в программу выражения типа 2 * 2 попросту не попадают, в лучшем случае там будет 4, а скорее всего, компилятор и четвёрку постарается как-нить убрать.
Построение дерева для выражения x-- - --x;
В этом выражении присутствует 3 операции, причём две из них(--) имеют более высокий приоритет, чем третья (-). Дерево такое:
-
/ \
x-- --xОчевидно, что в данном случае должны сначала выполнится декременты, а лишь потом - вычитание. Но стандарт особо описывает данную ситуацию, утверждая, что порядок выполнения самих декриментов НЕ определён. А раз так, то возможно всего два варианта(в начале x равен 10):
1) сначала выполняется x-- (10->9)
затем второй --x (9->8)
т.к. результатом x-- является x, то получается 10-8 == 2
2) второй случай --x (10->9)
x-- (9->8 результат 9)
9-9 == 0.
Теория - прекрасная штука. Проверяем
#include <stdio.h>
int main()
{
int x;
printf("Введите число: ");
scanf("%d", &x);
printf("\nx-- - --x = %d\n", x-- - --x);
return 0;
}
ksu@ksu:~/test$ gcc -Wall -o m m.c
m.c: В функции ‘main’:
m.c:8:32: предупреждение: операция над ‘x’ может дать неопределенный результат
ksu@ksu:~/test$ ./m
Введите число: 10
x-- - --x = 1
facepalm :O
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)


