鱼C论坛

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

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

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

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

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

x
当z--的值为0的时候,再判断z--的值是某为真还是会再--吗?
之前论坛有大佬给我讲了副作用和顺序点,但是我还能没能get到它的意思,while语句这里好像没有顺序点,z的--是什么时候发生的呢

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(void)
  4. {
  5.     int z = 2;
  6.     while (z--)
  7.     {
  8.         printf("z=%d\n", z);
  9.     }
  10.     printf("z=%d\n", z);
  11.     system("pause");
  12.     return 0;
  13. }
复制代码
最佳答案
2023-2-5 09:48:40
本帖最后由 两手空空儿 于 2023-2-5 10:09 编辑
  1. while (z--)
  2.     {
  3.         printf("z=%d\n", z);
  4.     }

  5. 等效如下
  6. int temp = z;
  7. z--;
  8. while (temp)
  9.     {
  10.         printf("z=%d\n", z);
  11.     }

  12. 后--运算的时候,编译器会先copy 一个副本,然后--,用副本参加运算
  13. 前--是直接--
复制代码
想知道小甲鱼最近在做啥?请访问 -> 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 编辑
  1. while (z--)
  2.     {
  3.         printf("z=%d\n", z);
  4.     }

  5. 等效如下
  6. int temp = z;
  7. z--;
  8. while (temp)
  9.     {
  10.         printf("z=%d\n", z);
  11.     }

  12. 后--运算的时候,编译器会先copy 一个副本,然后--,用副本参加运算
  13. 前--是直接--
复制代码

评分

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

查看全部评分

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

使用道具 举报

发表于 2023-2-5 10:31:12 | 显示全部楼层
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(void)
  4. {
  5.     1149:        55                           pushq  %rbp
  6.     114a:        48 89 e5                     movq   %rsp,%rbp
  7.     114d:        48 83 ec 10                  subq   $0x10,%rsp
  8.     int z = 2;
  9.     1151:        c7 45 fc 02 00 00 00         movl   $0x2,-0x4(%rbp)
  10.     while (z--)
  11.     1158:        eb 19                        jmp    1173 <main+0x2a>
  12.     {
  13.         printf("z=%d\n", z);
  14.     115a:        8b 45 fc                     movl   -0x4(%rbp),%eax
  15.     115d:        89 c6                        movl   %eax,%esi
  16.     115f:        48 8d 05 9e 0e 00 00         leaq   0xe9e(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
  17.     1166:        48 89 c7                     movq   %rax,%rdi
  18.     1169:        b8 00 00 00 00               movl   $0x0,%eax
  19.     116e:        e8 cd fe ff ff               callq  1040 <printf@plt>
  20.     while (z--)
  21.     1173:        8b 45 fc                     movl   -0x4(%rbp),%eax
  22.     1176:        8d 50 ff                     leal   -0x1(%rax),%edx
  23.     1179:        89 55 fc                     movl   %edx,-0x4(%rbp)
  24.     117c:        85 c0                        testl  %eax,%eax
  25.     117e:        75 da                        jne    115a <main+0x11>
  26.     }
  27.     printf("z=%d\n", z);
  28.     1180:        8b 45 fc                     movl   -0x4(%rbp),%eax
  29.     1183:        89 c6                        movl   %eax,%esi
  30.     1185:        48 8d 05 78 0e 00 00         leaq   0xe78(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
  31.     118c:        48 89 c7                     movq   %rax,%rdi
  32.     118f:        b8 00 00 00 00               movl   $0x0,%eax
  33.     1194:        e8 a7 fe ff ff               callq  1040 <printf@plt>
  34.     system("pause");
  35.     1199:        48 8d 05 6a 0e 00 00         leaq   0xe6a(%rip),%rax        # 200a <_IO_stdin_used+0xa>
  36.     11a0:        48 89 c7                     movq   %rax,%rdi
  37.     11a3:        e8 88 fe ff ff               callq  1030 <system@plt>
  38.     return 0;
  39.     11a8:        b8 00 00 00 00               movl   $0x0,%eax
  40. }
  41.     11ad:        c9                           leaveq
  42.     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看看

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(void)
  4. {
  5.     1149:        55                           pushq  %rbp
  6.     114a:        48 89 e5                     movq   %rsp,%rbp
  7.     114d:        48 83 ec 10                  subq   $0x10,%rsp
  8.     int z = 2;
  9.     1151:        c7 45 fc 02 00 00 00         movl   $0x2,-0x4(%rbp)
  10.     while (--z)
  11.     1158:        eb 19                        jmp    1173 <main+0x2a>
  12.     {
  13.         printf("z=%d\n", z);
  14.     115a:        8b 45 fc                     movl   -0x4(%rbp),%eax
  15.     115d:        89 c6                        movl   %eax,%esi
  16.     115f:        48 8d 05 9e 0e 00 00         leaq   0xe9e(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
  17.     1166:        48 89 c7                     movq   %rax,%rdi
  18.     1169:        b8 00 00 00 00               movl   $0x0,%eax
  19.     116e:        e8 cd fe ff ff               callq  1040 <printf@plt>
  20.     while (--z)
  21.     1173:        83 6d fc 01                  subl   $0x1,-0x4(%rbp)
  22.     1177:        83 7d fc 00                  cmpl   $0x0,-0x4(%rbp)
  23.     117b:        75 dd                        jne    115a <main+0x11>
  24.     }
  25.     printf("z=%d\n", z);
  26.     117d:        8b 45 fc                     movl   -0x4(%rbp),%eax
  27.     1180:        89 c6                        movl   %eax,%esi
  28.     1182:        48 8d 05 7b 0e 00 00         leaq   0xe7b(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
  29.     1189:        48 89 c7                     movq   %rax,%rdi
  30.     118c:        b8 00 00 00 00               movl   $0x0,%eax
  31.     1191:        e8 aa fe ff ff               callq  1040 <printf@plt>
  32.     system("pause");
  33.     1196:        48 8d 05 6d 0e 00 00         leaq   0xe6d(%rip),%rax        # 200a <_IO_stdin_used+0xa>
  34.     119d:        48 89 c7                     movq   %rax,%rdi
  35.     11a0:        e8 8b fe ff ff               callq  1030 <system@plt>
  36.     return 0;
  37.     11a5:        b8 00 00 00 00               movl   $0x0,%eax
  38. }
  39.     11aa:        c9                           leaveq
  40.     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 | 显示全部楼层
可以用这个程序研究研究在底层是怎么做的

  1. #include <stdio.h>

  2. int main(void) {
  3.     int a = 1;
  4.     int b = 2;
  5.     a = ++b;
  6.     a = --b;
  7.     a = b++;
  8.     a = b--;
  9.     return 0;
  10. }
复制代码

  1. #include <stdio.h>

  2. int main(void) {
  3.     1119:        55                           pushq  %rbp
  4.     111a:        48 89 e5                     movq   %rsp,%rbp
  5.     int a = 1;
  6.     111d:        c7 45 f8 01 00 00 00         movl   $0x1,-0x8(%rbp)
  7.     int b = 2;
  8.     1124:        c7 45 fc 02 00 00 00         movl   $0x2,-0x4(%rbp)
  9.     a = ++b;
  10.     112b:        83 45 fc 01                  addl   $0x1,-0x4(%rbp)
  11.     112f:        8b 45 fc                     movl   -0x4(%rbp),%eax
  12.     1132:        89 45 f8                     movl   %eax,-0x8(%rbp)
  13.     a = --b;
  14.     1135:        83 6d fc 01                  subl   $0x1,-0x4(%rbp)
  15.     1139:        8b 45 fc                     movl   -0x4(%rbp),%eax
  16.     113c:        89 45 f8                     movl   %eax,-0x8(%rbp)
  17.     a = b++;
  18.     113f:        8b 45 fc                     movl   -0x4(%rbp),%eax
  19.     1142:        8d 50 01                     leal   0x1(%rax),%edx
  20.     1145:        89 55 fc                     movl   %edx,-0x4(%rbp)
  21.     1148:        89 45 f8                     movl   %eax,-0x8(%rbp)
  22.     a = b--;
  23.     114b:        8b 45 fc                     movl   -0x4(%rbp),%eax
  24.     114e:        8d 50 ff                     leal   -0x1(%rax),%edx
  25.     1151:        89 55 fc                     movl   %edx,-0x4(%rbp)
  26.     1154:        89 45 f8                     movl   %eax,-0x8(%rbp)
  27.     return 0;
  28.     1157:        b8 00 00 00 00               movl   $0x0,%eax
  29. }
  30.     115c:        5d                           popq   %rbp
  31.     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-5-1 13:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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