这个问题是因为这个帖子而起, 也是这段代码有点不明白. 和自己预期的值不一样, 所以就编译反汇编看了下.
编译工具: Code:blocks(GCC), CPU(Intel Core i3 32位), OS(windows 7 / 32bit).
参考书籍: 深入理解计算机系统(Bryant & Hallaron)
更多了解关于 volatile 可以参考: http://blog.youkuaiyun.com/kissmonx/article/details/7724757
#include <stdio.h>
int main(int argc, char ** argv)
{
volatile int u = 0; // 我对这个也是纳闷, 难道和编译器的优化有关??? 反汇编看了下. 大致有点了解了.
u = u++ + ++u; // 如果写作三个 '+' 连一块(u+++ +u 除外), 就会报出 "自增操作数必须是左值" 的错误.
printf("%d\n", u); // 结果是 1
return 0;
}
汇编格式为 AT&T, 如果要产生 intel 格式的可以加编译选项如:-masm=intel
004013B7 push %ebp
004013B8 mov %esp,%ebp
004013BA and $0xfffffff0,%esp
004013BD sub $0x20,%esp // 分配栈空间
004013C0 call 0x401920 <__main>
004013C5 movl $0x0,0x1c(%esp)
004013CD mov 0x1c(%esp),%edx
004013D1 mov 0x1c(%esp),%eax
004013D5 inc %eax // u 自增一次
004013D6 mov %eax,0x1c(%esp) // volatile 变量每次取值都要去内存处, 防变量被意外修改而不知(这里进行的是存储器(基址 + 偏移量)寻址).
004013DA add %edx,%eax // 1 + 0
004013DC mov %eax,0x1c(%esp) // 然后就是在寄存器和 u 的内存地址处来回转悠, u 的值在这过程没有改变. 和其他情况确实不一样.
004013E0 lea 0x1(%edx),%eax // %eax 值为 0x1 + 0
004013E3 mov %eax,0x1c(%esp) // 写入内存
004013E7 mov 0x1c(%esp),%eax // 重新加载
004013EB mov %eax,0x4(%esp) // 将 %eax 送入栈顶之下的 4 字节处, 准备输出, 栈顶要载入新值.
004013EF movl $0x408064,(%esp) // 将返回地址保存在栈顶
004013F6 call 0x40138c <printf>
004013FB mov $0x0,%eax // 返回 0
00401400 leave
00401401 ret // 初学者, 注解如有误, 请指出, Thx.
// 作为对比, 这个是不加 volatile 修饰的变量运算的结果.
#include <stdio.h>
int main(int argc, char ** argv)
{
int u = 0;
u = u++ + ++u;
printf("%d\n", u); // 结果是 3
return 0;
}
反汇编的结果作为对比可以看出差别:
004013B7 push %ebp
004013B8 mov %esp,%ebp
004013BA and $0xfffffff0,%esp
004013BD sub $0x20,%esp
004013C0 call 0x401918 <__main>
004013C5 movl $0x0,0x1c(%esp)
004013CD incl 0x1c(%esp) // 第一次出现自增指令 1
004013D1 mov 0x1c(%esp),%eax // 看到没, 少用了一个寄存器, ^_^
004013D5 add %eax,%eax // 使用 add 指令 1 + 1.
004013D7 mov %eax,0x1c(%esp) // 写入 2
004013DB incl 0x1c(%esp) // 第一次出现自增指令 2 + 1
004013DF mov 0x1c(%esp),%eax // 加载
004013E3 mov %eax,0x4(%esp) // 准备输出
004013E7 movl $0x408064,(%esp)
004013EE call 0x40138c <printf>
004013F3 mov $0x0,%eax
004013F8 leave
004013F9 ret