G
N
I
D
A
O
L

如何理解strcpy函数中的赋值语句?

关于 strcpy 函数的赋值语句

如何理解while (*s++ = *t++)

void strcpy(char *s, char *t)
{ 
    while (*s++ = *t++);
}

该语句等价于while (*(s++) = *(t++))

赋值语句的结合方向是自右往左,所以从右往左读,可以将*(s++) = *(t++)拆成两条语句:

temp = *(t++);
*(s++) = temp;

也即代码段 A:

temp = *t;
t++;
*s = temp;
s++;

赋值语句实际上是一个表达式,等于赋值运算符右边表达式的结果,比如a = b的结果是b。这里右边表达式是*(t++),结果是*t先使用,后自增),因此原代码可等价于代码段 B:

while (*t != '\0'){
  *(s++) = *(t++);
}

代码段 A 和 B 结合在一起:

char temp = *t;
while (temp != '\0'){
    temp = *t;
    t++;
    *s = temp;
    s++;
}

需要提醒的是,平时不要写这样的代码,可读性较差。

一些汇编

*s++ = *t++的汇编:

mov     rdx, QWORD PTR [rbp-16]  ; t 存入 rdx
lea     rax, [rdx+1]             ; t+1,然后存入 rax
mov     QWORD PTR [rbp-16], rax  ; rax 再压回栈中,供函数使用
mov     rax, QWORD PTR [rbp-8]   ; s 存入 rax
lea     rcx, [rax+1]             ; s+1,然后存入 rcx
mov     QWORD PTR [rbp-8], rcx   ; rcx 再压回栈中,供函数使用
movzx   edx, BYTE PTR [rdx]      ; rdx 所指向的内容即 *t 存入 edx
mov     BYTE PTR [rax], dl       ; edx 的低 8 位内容存入 rax 所指向的内容即 *s

strcpy 的汇编:

strcpy(char*, char*):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     QWORD PTR [rbp-16], rsi  ; 以上均为调用函数前的操作,不用理会
.L3:
        mov     rdx, QWORD PTR [rbp-16]  ; t 存入 rdx
        lea     rax, [rdx+1]             ; t+1,然后存入 rax(rax = t+1)
        mov     QWORD PTR [rbp-16], rax  ; rax 再压回栈中,供函数使用
        mov     rax, QWORD PTR [rbp-8]   ; s 存入 rax
        lea     rcx, [rax+1]             ; s+1,然后存入 rcx(rcx = s+1)
        mov     QWORD PTR [rbp-8], rcx   ; rcx 再压回栈中,供函数使用
        movzx   edx, BYTE PTR [rdx]      ; rdx 所指向的内容即 *t 存入 edx
        mov     BYTE PTR [rax], dl       ; edx 的低 8 位内容存入 rax 所指向的内容即 *s(*s = *t)
        movzx   eax, BYTE PTR [rax]      ; rax 所指向的内容即 *t 存入 eax
        test    al, al                   ; 下面判断 eax 即 *t 是否为 0,test 指令是按位与运算
        setne   al
        test    al, al
        je      .L4
        jmp     .L3
.L4:
        nop
        pop     rbp
        ret
posted @ 2023-03-18 20:02  漫舞八月(Mount256)  阅读(28)  评论(0编辑  收藏  举报