鱼C论坛

 找回密码
 立即注册
查看: 2472|回复: 16

[已解决]关于运算符的问题

[复制链接]
发表于 2023-2-4 20:46:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
当z--的值为0的时候,再判断z--的值是某为真还是会再--吗?
之前论坛有大佬给我讲了副作用和顺序点,但是我还能没能get到它的意思,while语句这里好像没有顺序点,z的--是什么时候发生的呢
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int z = 2;
    while (z--)
    {
        printf("z=%d\n", z);
    }
    printf("z=%d\n", z);
    system("pause");
    return 0;
}
最佳答案
2023-2-5 09:48:40
本帖最后由 两手空空儿 于 2023-2-5 10:09 编辑
while (z--)
    {
        printf("z=%d\n", z);
    }

等效如下
int temp = z;
z--;
while (temp)
    {
        printf("z=%d\n", z);
    }

后--运算的时候,编译器会先copy 一个副本,然后--,用副本参加运算
前--是直接--
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-2-4 20:48:31 | 显示全部楼层
我好像总是理解成z的值不为0了就不会执行整个while循环了,但是实际是还是执行了第六行,然后z--再跳过while循环吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-4 20:49:17 | 显示全部楼层
然后最二个printf那里我以为会打印0
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-4 21:53:42 From FishC Mobile | 显示全部楼层
full expression 之间是有顺序点的
expression statement (大体上就是一个语句就是一个表达式,比如这里的 printf 调用)和 while 的条件语句都是 full expression,所以它们的求值之间有顺序点
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 09:48:40 | 显示全部楼层    本楼为最佳答案   
本帖最后由 两手空空儿 于 2023-2-5 10:09 编辑
while (z--)
    {
        printf("z=%d\n", z);
    }

等效如下
int temp = z;
z--;
while (temp)
    {
        printf("z=%d\n", z);
    }

后--运算的时候,编译器会先copy 一个副本,然后--,用副本参加运算
前--是直接--

评分

参与人数 1荣誉 +5 鱼币 +1 贡献 +3 收起 理由
1613551 + 5 + 1 + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 10:31:12 | 显示全部楼层
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    1149:        55                           pushq  %rbp
    114a:        48 89 e5                     movq   %rsp,%rbp
    114d:        48 83 ec 10                  subq   $0x10,%rsp
    int z = 2;
    1151:        c7 45 fc 02 00 00 00         movl   $0x2,-0x4(%rbp)
    while (z--)
    1158:        eb 19                        jmp    1173 <main+0x2a>
    {
        printf("z=%d\n", z);
    115a:        8b 45 fc                     movl   -0x4(%rbp),%eax
    115d:        89 c6                        movl   %eax,%esi
    115f:        48 8d 05 9e 0e 00 00         leaq   0xe9e(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1166:        48 89 c7                     movq   %rax,%rdi
    1169:        b8 00 00 00 00               movl   $0x0,%eax
    116e:        e8 cd fe ff ff               callq  1040 <printf@plt>
    while (z--)
    1173:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1176:        8d 50 ff                     leal   -0x1(%rax),%edx
    1179:        89 55 fc                     movl   %edx,-0x4(%rbp)
    117c:        85 c0                        testl  %eax,%eax
    117e:        75 da                        jne    115a <main+0x11>
    }
    printf("z=%d\n", z);
    1180:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1183:        89 c6                        movl   %eax,%esi
    1185:        48 8d 05 78 0e 00 00         leaq   0xe78(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    118c:        48 89 c7                     movq   %rax,%rdi
    118f:        b8 00 00 00 00               movl   $0x0,%eax
    1194:        e8 a7 fe ff ff               callq  1040 <printf@plt>
    system("pause");
    1199:        48 8d 05 6a 0e 00 00         leaq   0xe6a(%rip),%rax        # 200a <_IO_stdin_used+0xa>
    11a0:        48 89 c7                     movq   %rax,%rdi
    11a3:        e8 88 fe ff ff               callq  1030 <system@plt>
    return 0;
    11a8:        b8 00 00 00 00               movl   $0x0,%eax
}
    11ad:        c9                           leaveq
    11ae:        c3                           retq

    1173:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1176:        8d 50 ff                     leal   -0x1(%rax),%edx
    1179:        89 55 fc                     movl   %edx,-0x4(%rbp)
    117c:        85 c0                        testl  %eax,%eax
    117e:        75 da                        jne    115a <main+0x11>
上面这5条指令就是while(z--)对应的汇编语言指令
其实应该是6条指令
    1158:        eb 19                        jmp    1173 <main+0x2a>
这个应该也属于是 while(z--) 语句


首先,一上来先给z的值赋值成2
    1151:        c7 45 fc 02 00 00 00         movl   $0x2,-0x4(%rbp)
-0x4(%rbp) 就是 z 的地址

然后就是一个jmp
    1158:        eb 19                        jmp    1173 <main+0x2a>
这个jmp让cpu从1173的位置继续执行,就是
    1173:        8b 45 fc                     movl   -0x4(%rbp),%eax
这就是while语句的部分了
先把z的值读取出来,读取到eax里面
    1176:        8d 50 ff                     leal   -0x1(%rax),%edx
然后给eax的值减 1
减 1 之后的结果给edx
一开始z的值是2
    1173:        8b 45 fc                     movl   -0x4(%rbp),%eax
把这个2读取到eax里面
    1176:        8d 50 ff                     leal   -0x1(%rax),%edx
2 - 1 = 1
把1给edx

    1179:        89 55 fc                     movl   %edx,-0x4(%rbp)
把edx中的这个1写回到z里面
执行完这条指令之后,z的值就变成1了

    117c:        85 c0                        testl  %eax,%eax
接下来判断eax中的值,eax中的值是2
    117e:        75 da                        jne    115a <main+0x11>
所以转移到 115a的地方继续执行指令
115a就是去执行printf
        printf("z=%d\n", z);
    115a:        8b 45 fc                     movl   -0x4(%rbp),%eax
    115d:        89 c6                        movl   %eax,%esi
    115f:        48 8d 05 9e 0e 00 00         leaq   0xe9e(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1166:        48 89 c7                     movq   %rax,%rdi
    1169:        b8 00 00 00 00               movl   $0x0,%eax
    116e:        e8 cd fe ff ff               callq  1040 <printf@plt>

执行完这个printf之后又来到了while的部分
116e是printf的最后一条指令,这条指令的下一条指令是1173
就是while的部分
    1173:        8b 45 fc                     movl   -0x4(%rbp),%eax
一样的,把z中的1读取到eax
    1176:        8d 50 ff                     leal   -0x1(%rax),%edx
给这个值减 1 ,结果写到edx
就是把1 - 1 的结果写到edx
就是把 0 写到edx
    1179:        89 55 fc                     movl   %edx,-0x4(%rbp)
然后又把0写到z里面
执行完这条指令之后z里面保存的值就是0了

    117c:        85 c0                        testl  %eax,%eax
    117e:        75 da                        jne    115a <main+0x11>
然后判断eax里面的值是不是0,eax中的值是1,不是0
所以再跳回去执行printf
执行完printf之后又来到了while

    1173:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1176:        8d 50 ff                     leal   -0x1(%rax),%edx
    1179:        89 55 fc                     movl   %edx,-0x4(%rbp)
    117c:        85 c0                        testl  %eax,%eax
    117e:        75 da                        jne    115a <main+0x11>
还是这个
把z里面的那个0读取到eax
减1的结果写到edx
0 - 1 等于几?
等于 -1,没错,把-1写回z里面
    1179:        89 55 fc                     movl   %edx,-0x4(%rbp)
执行完这条指令之后,z里面保存的就是-1
然后接下来判断eax里面的值是不是0
这一次eax里面的值是0了
那就不跳上去了,就是说117e的这条jne指令执行完之后要执行1180位置的指令,而不是之前的115a了
    printf("z=%d\n", z);
    1180:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1183:        89 c6                        movl   %eax,%esi
    1185:        48 8d 05 78 0e 00 00         leaq   0xe78(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    118c:        48 89 c7                     movq   %rax,%rdi
    118f:        b8 00 00 00 00               movl   $0x0,%eax
    1194:        e8 a7 fe ff ff               callq  1040 <printf@plt>
1180开始又是一个printf
再之后就是system函数了
然后就没了

评分

参与人数 1荣誉 +5 贡献 +3 收起 理由
1613551 + 5 + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 10:44:52 | 显示全部楼层
我们把z--改成--z看看
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    1149:        55                           pushq  %rbp
    114a:        48 89 e5                     movq   %rsp,%rbp
    114d:        48 83 ec 10                  subq   $0x10,%rsp
    int z = 2;
    1151:        c7 45 fc 02 00 00 00         movl   $0x2,-0x4(%rbp)
    while (--z)
    1158:        eb 19                        jmp    1173 <main+0x2a>
    {
        printf("z=%d\n", z);
    115a:        8b 45 fc                     movl   -0x4(%rbp),%eax
    115d:        89 c6                        movl   %eax,%esi
    115f:        48 8d 05 9e 0e 00 00         leaq   0xe9e(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1166:        48 89 c7                     movq   %rax,%rdi
    1169:        b8 00 00 00 00               movl   $0x0,%eax
    116e:        e8 cd fe ff ff               callq  1040 <printf@plt>
    while (--z)
    1173:        83 6d fc 01                  subl   $0x1,-0x4(%rbp)
    1177:        83 7d fc 00                  cmpl   $0x0,-0x4(%rbp)
    117b:        75 dd                        jne    115a <main+0x11>
    }
    printf("z=%d\n", z);
    117d:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1180:        89 c6                        movl   %eax,%esi
    1182:        48 8d 05 7b 0e 00 00         leaq   0xe7b(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1189:        48 89 c7                     movq   %rax,%rdi
    118c:        b8 00 00 00 00               movl   $0x0,%eax
    1191:        e8 aa fe ff ff               callq  1040 <printf@plt>
    system("pause");
    1196:        48 8d 05 6d 0e 00 00         leaq   0xe6d(%rip),%rax        # 200a <_IO_stdin_used+0xa>
    119d:        48 89 c7                     movq   %rax,%rdi
    11a0:        e8 8b fe ff ff               callq  1030 <system@plt>
    return 0;
    11a5:        b8 00 00 00 00               movl   $0x0,%eax
}
    11aa:        c9                           leaveq
    11ab:        c3                           retq

一开始一样,给z赋值成2
然后跳到1173执行while

    1173:        83 6d fc 01                  subl   $0x1,-0x4(%rbp)
这个是把z的值减 1
或者你可以理解成是
先把z的值读取出来,然后减1,然后再把减1之后的结果写回到z里面
这1条指令做了这3件事
把z值读取出来,减1,再写回去

    1177:        83 7d fc 00                  cmpl   $0x0,-0x4(%rbp)
然后判断z是不是0

    117b:        75 dd                        jne    115a <main+0x11>
不是0就跳回去执行printf

评分

参与人数 1荣誉 +5 贡献 +3 收起 理由
1613551 + 5 + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 10:47:31 | 显示全部楼层
可以用这个程序研究研究在底层是怎么做的
#include <stdio.h>

int main(void) {
    int a = 1;
    int b = 2;
    a = ++b;
    a = --b;
    a = b++;
    a = b--;
    return 0;
}
#include <stdio.h>

int main(void) {
    1119:        55                           pushq  %rbp
    111a:        48 89 e5                     movq   %rsp,%rbp
    int a = 1;
    111d:        c7 45 f8 01 00 00 00         movl   $0x1,-0x8(%rbp)
    int b = 2;
    1124:        c7 45 fc 02 00 00 00         movl   $0x2,-0x4(%rbp)
    a = ++b;
    112b:        83 45 fc 01                  addl   $0x1,-0x4(%rbp)
    112f:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1132:        89 45 f8                     movl   %eax,-0x8(%rbp)
    a = --b;
    1135:        83 6d fc 01                  subl   $0x1,-0x4(%rbp)
    1139:        8b 45 fc                     movl   -0x4(%rbp),%eax
    113c:        89 45 f8                     movl   %eax,-0x8(%rbp)
    a = b++;
    113f:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1142:        8d 50 01                     leal   0x1(%rax),%edx
    1145:        89 55 fc                     movl   %edx,-0x4(%rbp)
    1148:        89 45 f8                     movl   %eax,-0x8(%rbp)
    a = b--;
    114b:        8b 45 fc                     movl   -0x4(%rbp),%eax
    114e:        8d 50 ff                     leal   -0x1(%rax),%edx
    1151:        89 55 fc                     movl   %edx,-0x4(%rbp)
    1154:        89 45 f8                     movl   %eax,-0x8(%rbp)
    return 0;
    1157:        b8 00 00 00 00               movl   $0x0,%eax
}
    115c:        5d                           popq   %rbp
    115d:        c3                           retq

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 10:51:19 | 显示全部楼层
    a = ++b;
    112b:        83 45 fc 01                  addl   $0x1,-0x4(%rbp)
    112f:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1132:        89 45 f8                     movl   %eax,-0x8(%rbp)

    112b:        83 45 fc 01                  addl   $0x1,-0x4(%rbp)
把b的值加1
    112f:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1132:        89 45 f8                     movl   %eax,-0x8(%rbp)
把b的值写到eax,然后再把eax写到a里面


    a = b++;
    113f:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1142:        8d 50 01                     leal   0x1(%rax),%edx
    1145:        89 55 fc                     movl   %edx,-0x4(%rbp)
    1148:        89 45 f8                     movl   %eax,-0x8(%rbp)

    113f:        8b 45 fc                     movl   -0x4(%rbp),%eax
    1142:        8d 50 01                     leal   0x1(%rax),%edx
把b的值读取到eax,减1的结果写到edx

    1145:        89 55 fc                     movl   %edx,-0x4(%rbp)
把edx里面的值写回b里面
就是减1之后的那个值

    1148:        89 45 f8                     movl   %eax,-0x8(%rbp)
把eax里面的值写到a里面
eax里面的值是减1之前的

评分

参与人数 1荣誉 +4 贡献 +3 收起 理由
1613551 + 4 + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-5 15:04:21 | 显示全部楼层
人造人 发表于 2023-2-5 10:51
a = ++b;
    112b:        83 45 fc 01                  addl   $0x1,-0x4(%rbp)
    112f:        ...


大佬我看不懂这些,呜呜呜,因为考试只考c语言和数据结构我目前就只学了c语言和数据结构
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-5 15:05:19 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 15:07:38 | 显示全部楼层
1613551 发表于 2023-2-5 15:04
大佬我看不懂这些,呜呜呜,因为考试只考c语言和数据结构我目前就只学了c语言和数据结构

哪里看不懂?
addl   $0x1,-0x4(%rbp)
给b的值加1,看不懂?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-5 15:14:58 | 显示全部楼层
人造人 发表于 2023-2-5 15:07
哪里看不懂?
addl   $0x1,-0x4(%rbp)
给b的值加1,看不懂?

说实话全部都没看懂,从说是汇编语言指令后面就看不懂了
长图_2023-02-05.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 15:30:55 | 显示全部楼层
1613551 发表于 2023-2-5 15:14
说实话全部都没看懂,从说是汇编语言指令后面就看不懂了

    int a = 1;
    111d:        c7 45 f8 01 00 00 00         movl   $0x1,-0x8(%rbp)

movl   $0x1,-0x8(%rbp)
就是把1赋值给变量a,这个不难吧?
哪里不懂?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-5 15:50:15 | 显示全部楼层
人造人 发表于 2023-2-5 15:30
int a = 1;
    111d:        c7 45 f8 01 00 00 00         movl   $0x1,-0x8(%rbp)


就是int a=1;这些我懂,然后其余的像是
111d:        c7 45 f8 01 00 00 00         movl   $0x1,-0x8(%rbp)

movl   $0x1,-0x8(%rbp)
这些就没看懂了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-2-5 16:08:29 | 显示全部楼层
1613551 发表于 2023-2-5 15:50
就是int a=1;这些我懂,然后其余的像是
111d:        c7 45 f8 01 00 00 00         movl   $0x1,-0x ...

movl   $0x1,-0x8(%rbp)
其他不用管,就看这个就可以了
movl一条指令
movl a, b
把a复制给b
$0x1就是1,但是要加$,语法要求这样
-0x8(%rbp)
这个是变量b的地址

movl   $0x1,-0x8(%rbp)
把1写到b这个变量里面
给变量b赋值成1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-2-5 16:10:12 | 显示全部楼层
人造人 发表于 2023-2-5 16:08
movl   $0x1,-0x8(%rbp)
其他不用管,就看这个就可以了
movl一条指令

懂了懂了,我说怎么根本看不懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-25 21:10

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表