编译环境gcc4.4.1
如下代码
int a = 4;
a += (a++);
printf("%d\n",a);
a = 4;
a += (++a) ;
printf("%d\n",a);
a = 4;
(++a) += a;
printf("%d\n",a);
a = 4;
(a++) += a;//a++不能作为左值参加运算。
printf("%d\n",a);
a = 4;
(++a) += (a++);
printf("%d\n",a);
打印的值为9,10,10,11。汇编代码如下:
# a += (a++);
00401326 movl $0x4,0x1c(%esp)
0040132E mov 0x1c(%esp),%eax
00401332 add %eax,%eax
00401334 mov %eax,0x1c(%esp)
00401338 incl 0x1c(%esp)
0040133C mov 0x1c(%esp),%eax
00401340 mov %eax,0x4(%esp)
00401344 movl $0x46f024,(%esp)
0040134B call 0x41c750 <printf>
# a += (++a) ;
00401350 movl $0x4,0x1c(%esp)
00401358 incl 0x1c(%esp)
0040135C mov 0x1c(%esp),%eax
00401360 add %eax,%eax
00401362 mov %eax,0x1c(%esp)
00401366 mov 0x1c(%esp),%eax
0040136A mov %eax,0x4(%esp)
0040136E movl $0x46f024,(%esp)
00401375 call 0x41c750 <printf>
# (++a) += a;
0040137A movl $0x4,0x1c(%esp)
00401382 incl 0x1c(%esp)
00401386 mov 0x1c(%esp),%eax
0040138A add %eax,%eax
0040138C mov %eax,0x1c(%esp)
00401390 mov 0x1c(%esp),%eax
00401394 mov %eax,0x4(%esp)
00401398 movl $0x46f024,(%esp)
0040139F call 0x41c750 <printf>
#(++a) += (a++);
004013A4 movl $0x4,0x1c(%esp)
004013AC incl 0x1c(%esp)
004013B0 mov 0x1c(%esp),%eax
004013B4 add %eax,%eax
004013B6 mov %eax,0x1c(%esp)
004013BA incl 0x1c(%esp)
004013BE mov 0x1c(%esp),%eax
004013C2 mov %eax,0x4(%esp)
004013C6 movl $0x46f024,(%esp)
004013CD call 0x41c750 <printf>
可以看出,在运算过程中,++a优先级> += > a++
1)先运算a+a,然后再自增a
2),3)先运算++a,然后再a+a
4)先运算++a,然后a+a,然后a++
定义如下一个struct
struct T
{
int a;
int b[0];
int c;
};
打印各个成员的地址和大小,结果如下:
编译环境Code::Blocks 10.05
struct T t;
printf("%p:%d\n",&(t.a),sizeof(t.a));
printf("%p:%d\n",&(t.b),sizeof(t.b));
printf("%p:%d\n",&(t.c),sizeof(t.c));
0022FF38:4
0022FF3C:0
0022FF3C:4
可见定义的空数组,是不占任何空间的。其返回的内存地址是下一个可分配的地址。
如果在返回值为int的函数里,漏掉return,会发生什么情况?
编译工具:Code::Blocks 10.05,代码如下所示
#include <cstdio>
int f()
{
}
int main ()
{
printf("%d ",f());
printf("%d ",f());
printf("%d ",f());
return 0;
}
编译时,提示
In function 'int f()':|
warning: no return statement in function returning non-void|
但是能编译
Debug版本下结果如下:
1 2 2
Release版本下结果
0 0 0
下面分析一下为什么为发生这种情况:
从code:: blocks里面看到的 函数f的汇编代码
00401318 push %ebp
00401319 mov %esp,%ebp //正确的似乎是 mov %ebp %esp
0040131B leave
0040131C ret
如果函数f()如下定义
int f()
{
return 100;
}
则汇编代码是
00401318 push %ebp
00401319 mov %esp,%ebp
0040131B mov $0x64,%eax
00401320 leave
00401321 ret
接下来我们看一下整个main函数的汇编代码
00401322 push %ebp
00401323 mov %esp,%ebp
00401325 and $0xfffffff0,%esp
00401328 sub $0x10,%esp
0040132B call 0x401770 <__main>
00401330 call 0x401318 <f()>
00401335 mov %eax,0x4(%esp)
00401339 movl $0x403024,(%esp)
00401340 call 0x4019ac <printf>
00401345 call 0x401318 <f()>
0040134A mov %eax,0x4(%esp)//将返回值传递给%esp+0x04
0040134E movl $0x403024,(%esp)
00401355 call 0x4019ac <printf>
0040135A call 0x401318 <f()>
0040135F mov %eax,0x4(%esp)
00401363 movl $0x403024,(%esp)
0040136A call 0x4019ac <printf>
0040136F mov $0x0,%eax
00401374 leave
00401375 ret
从中我们可以看出,函数f()是将返回值通过EAX寄存器中,传递给调用它的代码。
如过我们漏掉了return intVal语句,在Debug模式下可能会导致,调用f()的代码得到的是上次的其他函数被调用的返回值。
在进入main之后EAX通常会被初始化为0x01.所以第一个f() 返回值为1.
printf 打印了“1 ”两个字符之后,返回值为2,所以第二个f()返回值为2。
printf 打印了“2 ”两个字符之后,返回值为2,所以第三个f()返回值为2。
在Release版本下,函数f()被优化,printf直接打印数字0。
401320: push %ebp
401321: mov %esp,%ebp
401323: and $0xfffffff0,%esp
401326: sub $0x10,%esp
401329: call 0x401760
40132e: movl $0x0,0x4(%esp)
401335:
401336: movl $0x403024,(%esp)
40133d: call 0x40199c
401342: movl $0x0,0x4(%esp)
401349:
40134a: movl $0x403024,(%esp)
401351: call 0x40199c
401356: movl $0x0,0x4(%esp)
40135d:
40135e: movl $0x403024,(%esp)
401365: call 0x40199c
40136a: xor %eax,%eax
40136c: leave
40136d: ret