2010-07-19 4 views
8

Можно создать дубликат:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)пост-оператор инкремента: Неожиданное поведение

Мой код выглядит следующим образом:

#include <stdio.h> 
int main() 
{ 
    int x = 10, y = 0; 
    x = x++; 
    printf("x: %d\n", x); 
    y = x++; 
    printf("y: %d\n", y); 
} 

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

x: 10 
y: 10 

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

Вместо этого, однако, я получаю это:

x: 11 
y: 11 

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

LCFI2: 
     movl $10, -4(%rbp) // this is x 
     movl $0, -8(%rbp) // this is y 
     incl -4(%rbp)  // x is simply incremented 
     movl -4(%rbp), %esi 
     leaq LC0(%rip), %rdi 
     movl $0, %eax 
     call _printf 
     movl -4(%rbp), %eax // now x is saved in a register, 
     movl %eax, -8(%rbp) // copied to y, 
     incl -4(%rbp)  // and finally incremented 
     movl -8(%rbp), %esi 
     leaq LC1(%rip), %rdi 
     movl $0, %eax 
     call _printf 

Что здесь происходит? Является ли GCC пытаться спасти меня от себя? У меня нет ссылки на язык, но я бы подумал, что это нарушает предполагаемую семантику.

+0

мерзости !!! – 2010-07-19 02:32:59

+0

http://en.wikipedia.org/wiki/Sequence_point – Ken

+0

В старые добрые времена 'a = 1 + a' на некоторых языках был мином, на который наступали все новые ошибки. –

ответ

13

Поведение не определено, так как нет промежуточной точки последовательности в x = x++, см., Например, C FAQ.

+0

Спасибо! Раньше я не знал о точках последовательности. – danben

4

Остается неопределенным на языке C относительно того, когда происходит сообщение post/pre-in/decment. Таким образом, такие заявления, как x = x++, не сформированы - избегайте их.

+1

Более точно вам не разрешается изменять переменную более одного раза в выражении. 6.5/2: * «Между предыдущей и следующей точкой последовательности объект должен иметь значение, которое его хранимое значение изменялось не более одного раза путем оценки выражения». * – sth

+2

@sth: Точнее, «более одного между точками последовательности». Возможно, что выражение содержит точку последовательности, и в этом случае изменение переменной более одного раза отлично. Например, '&&', '||' и оператор запятой могут образовывать точки последовательности в одном выражении. –

+0

@sth: Даже более точно, это не ограничение для кодера, это ограничение самой переменной. Ваше утверждение о том, что вам «не разрешено ...» не совсем правильно. Вы, возможно, допустили, это просто очень глупо делать :-) – paxdiablo

1

Когда у вас есть:

a = b++; 

, что происходит в том, что б сохраняется к и после того, как распайка делается б увеличивается на единицу. Так что если вы делаете:

x = x ++; 

и ранее х было 10, что будет происходить в 10 будет сохранен х и после (до вашего Printf делается) х увеличивается на единицу до 11. Вот почему 11 печатается.

2

Стандарты в сторону (поскольку это не определено в отношении стандарта), то, как он работал, так я ожидал.

Мое правило заключается в том, что для линии с x++, вы заменяете x++ с x и поставить x += 1 на следующей строке (или предыдущей линии для преинкремента).

После этого правило, ваш код должен быть написан так

#include <stdio.h> 
int main() 
{ 
    int x = 10, y = 0; 
    x = x; // x: 10 
    x += 1; // x: 11 
    printf("x: %d\n", x); 
    y = x; // y: 11 
    x += 1; // x: 12 
    printf("y: %d\n", y); 
}