Я пытаюсь лучше понять, как компиляторы производят код для выражений undefined, например. для следующего кода:
int main()
{
int i = 5;
i = i++;
return 0;
}
Это код ассемблера, сгенерированный gcc 4.8.2 (оптимизация выключена -O0, а Ive вставил мои собственные номера строк для справочных целей):
(gdb) disassemble main
Dump of assembler code for function main:
(1) 0x0000000000000000 <+0>: push %rbp
(2) 0x0000000000000001 <+1>: mov %rsp,%rbp
(3) 0x0000000000000004 <+4>: movl $0x5,-0x4(%rbp)
(4) 0x000000000000000b <+11>: mov -0x4(%rbp),%eax
(5) 0x000000000000000e <+14>: lea 0x1(%rax),%edx
(6) 0x0000000000000011 <+17>: mov %edx,-0x4(%rbp)
(7) 0x0000000000000014 <+20>: mov %eax,-0x4(%rbp)
(8) 0x0000000000000017 <+23>: mov $0x0,%eax
(9) 0x000000000000001c <+28>: pop %rbp
(10) 0x000000000000001d <+29>: retq
End of assembler dump.
Выполнение этого кода приводит к значению i
, оставшемуся при значении 5 (проверено с помощью оператора printf()
), т.е. i
, по-видимому, никогда не увеличивается. Я понимаю, что разные компиляторы будут оценивать/компилировать выражения undefined в differnet-путях, и это может быть просто так, как это делает gcc. Я мог бы получить другой результат с другим компилятором.
Что касается кода ассемблера, как я понимаю:
Игнорирование строки - 1-2 настройка указателей стека/базы и т.д.
строка 3/4 - это значение 5 для i
.
Может ли кто-нибудь объяснить, что происходит на линии 5-6? Похоже, что i
будет в конечном счете переназначить значение 5 (строка 7), но это операция инкремента (необходимая для операции приращения post i++
), просто оставленная/пропущенная компилятором в случае?