为了加深对" (* p)++"工作,我写了一些测试代码,如:
int main()
{
int a = 3;
int *p = &a;
int b = (*p)++;
int *q = p++;
int c = a++;
int d = c++;
printf("a = %d, b = %d, c = %d, d = %d, p = %#x, q = %#x\n",a, b, c, d, p, q);
}
输出为:a = 5,b = 3,c = 5,d = 4,p = 0xc6dc3490,q = 0xc6dc348c
但我的问题是关于程序集(代码是订单而不是关闭):
main:
push rbp
mov rbp, rsp
sub rsp, 48
;int a = 3 :
mov DWORD PTR [rbp-36], 3
;int *p = &a :
lea rax, [rbp-36]
mov QWORD PTR [rbp-8], rax
;int b = (*p)++ :
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
lea ecx, [rax+1] ;Flag1
mov rdx, QWORD PTR [rbp-8]
mov DWORD PTR [rdx], ecx
mov DWORD PTR [rbp-12], eax
;int *q = p++ :
mov rax, QWORD PTR [rbp-8] ;Flag2
lea rdx, [rax+4] ;Flag3
mov QWORD PTR [rbp-8], rdx
mov QWORD PTR [rbp-24], rax
;int c = a++;
mov eax, DWORD PTR [rbp-36]
lea edx, [rax+1] ;Flag4
mov DWORD PTR [rbp-36], edx
mov DWORD PTR [rbp-28], eax
;int d = c++;
mov eax, DWORD PTR [rbp-28]
lea edx, [rax+1] ;Flag5
mov DWORD PTR [rbp-28], edx
mov DWORD PTR [rbp-32], eax
... ... (ignore some)
请注意" Flagx"让我困惑的线条 从上面,我们知道 指针时: int * q = p ++ :
lea rdx, [rax+4] ;Flag3
在这里,' lea'似乎在' rax'中读取了addr值存储。和+4。然后转到' rdx'。
while: int c = a ++ 或 int d = c ++ :
lea edx, [rax+1] ;Flag4/Flag5
在这里,' lea'似乎在' rax'中读取了addr值存储的内容。 (这里是3)和+1,来到4并传递给#edx'。
但是!重点是' rax '在这两个方面,同一个。他们全都来自
mov rax, QWORD PTR [rbp-8] ;Flag2
正如我们所看到的,它们(Flag3和Flag4 / Flag5)看起来非常相似,但它们的工作方式基于相同的rax',怎么样?可以' lea'指令区分' rdx'和' edx / ecx'并得出不同的结果?
非常感谢你。
答案 0 :(得分:5)
在这里,'lea'似乎在'rax'(这里是3)中读取addr值存储的内容,而+1,来到4并传递给'edx'。
不,你错了。 lea edx, [rax+1]
不会更改rax
。 <{1}}在评估rax
指令之前已3
。
但是!关键是这两个陈述中的'rax'是相同的。他们全都来自
lea
不,你错了。 mov rax, QWORD PTR [rbp-8]
正在设置rax
。
可以使用不同的名称引用通用寄存器的不同部分。
mov eax, DWORD PTR [rbp-36]
这意味着当您写入 64 32 16 8 0
| | | | |
v v v v v
+----+----+----+----+----+----+----+----+
| | | | | | | | |
+----+----+----+----+----+----+----+----+
|<------------------------------------->| rax
|<----------------->| eax
|<------->| ax
|<-->| ah
|<-->| al
时,您也会写入eax
的下半部分(上半部分归零)。
所以,
rax
答案 1 :(得分:1)
p
和q
是您int
的指针,平台上int
的大小 4 。因此,递增p
实际上会将其值增加 4 。
int *q = p++;
mov rax, QWORD PTR [rbp-8] ; rax = p
lea rdx, [rax+4] ; same as rdx = rax + 4
mov QWORD PTR [rbp-8], rdx ; p = rdx
mov QWORD PTR [rbp-24], rax ; q = rax
c
是int
。因此,递增a
实际上只是将其值增加 1 。
c = a++;
mov eax, DWORD PTR [rbp-40] ; rax = a (yes modifying eax actually modifies rax)
lea edx, [rax+1] ; same as edx = rax + 1
mov DWORD PTR [rbp-40], edx ; a = edx
mov DWORD PTR [rbp-28], eax ; c = eax (eax still contains the inital value of a)
答案 2 :(得分:-1)
在行int *q = p++
中,地址指针递增。如您所知,int的大小为4个字节,int的大小是指针变量的大小,因此在汇编代码中您可以看到lea rdx, [rax+4]
。
但是在行int c = a++
中,变量a
的值正在增加。因此,在汇编代码中,您可以看到lea edx, [rax+1]
。
注意: int
的大小可能因编译器而异。但是根据基于GCC
的编译器,在您的情况下,int
长度为4个字节