04|控制逻辑:表达式和语句是如何协调程序运行的?
该思维导图由 AI 生成,仅供参考
表达式
- 深入了解
- 翻译
- 解释
- 总结
C语言中的表达式和语句是程序运行的关键控制单元。表达式由运算符和操作数组成,通过优先级和结合性决定计算顺序,编译器将其映射到抽象语法树上进行递归求值。语句是程序的基本构建块,包括复合语句和表达式语句等类型,以及选择、迭代和跳转语句。这些语句按顺序执行,构成程序的逻辑流程。 在选择语句部分,文章介绍了if...else和switch...case语句的编译器实现细节,包括汇编代码的分析和优化条件下的实现策略。在迭代语句部分,以do...while语句为例,讲解了迭代过程的汇编实现方式。跳转语句部分介绍了break、continue、return和goto语句的功能及其在程序执行流程中的作用。 总的来说,文章通过深入分析C语言中表达式和语句的实现细节,帮助读者更好地理解程序的执行流程和编译器的优化策略。对于想深入了解C语言底层实现的读者来说,这篇文章提供了宝贵的技术细节和实际示例,有助于加深对C语言程序执行机制的理解。
《深入 C 语言和程序运行原理》,新⼈⾸单¥59
全部留言(16)
- 最新
- 精选
- 奕置顶现在遇到了 汇编指令 比较多了,有些指令不知道做了什么, 有没有一个统一的地方可以方便进行查询的
作者回复: 这是一个好问题,可以 watch 一下我在 01 讲的提到的 GitHub 仓库哈,我会尽快把相关资料更新在里面的。
2021-12-1924 - liu_liu关于迭代语句中的 .L2 汇编代码段: // 把 v 放入 eax mov eax, DWORD PTR [rbp-4] // edx = rax-1 lea edx, [rax-1] // 把 edx 的值写入 rbp-4 地址 move DWROD PTR [rbp-4], edx 这段汇编的作用应该是用于 v-- 。 但有一些不太明白,为什么要使用 lea 指令呢?可直接用 move 指令?
作者回复: 这是一个很棒的问题! 如果使用 mov 指令,也是可以完成同样的功能的,只不过需要独立的两条指令,比如: - dec rax; - mov edx, rax 但使用 lea 指令,我们就可以仅通过一条机器指令来实现。相对于前者,其执行效率是不是更高呢?实际上,对于编译器来说,很多基本的四则运算都可以直接使用 lea 指令来实现,比如 lea eax, [123 + 4*ebx + esi],就是直接将 ebx 中的值乘以 4 再加上 123 和 esi 中的值。相较于使用 mov 的多条指令,lea 可以充分利用它在硬件中的电路特性,以更高的效率进行计算。
2021-12-1510 - pedro竟然有一种像当年读CSAPP第三章的感觉! 空语句用的少,多数时候用来做空循环体吧。
作者回复: 没错!这是一种常见的场景。举个例子: #include <stdio.h> int main() { char c; while ((c = getchar()) == ' '); printf("%c", c); }
2021-12-136 - qinsi维基上Duff's device的例子 send(to, from, count) register short *to, *from; register count; { register n = (count + 7) / 8; switch (count % 8) { case 0: do { *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while (--n > 0); } }
作者回复: 达夫设备是 switch 语句和循环展开的巧妙结合,我们会在 19 讲再来深入介绍哈!
2021-12-133 - 送过快递的码农老师 ,test/cmp 比较多指令,最终结果会在EFLAGS这个寄存器中么,j(cond)指令会根据这个寄存器做相应的跳动?
作者回复: 没错的,你的理解是正确的。
2021-12-152 - 阿妞老师,请问一下 下面代码的汇编,满足条件跳转到.L6,不满足就继续执行,但最后的v=20,是在.L6里面,只有跳转才执行,不跳转就不执行?从c上看,是无论满足不满足条件,都应该执行的呀,很疑惑! int test() { int v=20; if(v>10) { v--; v=10; } v=20; } test: push rbp mov rbp, rsp mov DWORD PTR [rbp-4], 20 cmp DWORD PTR [rbp-4], 10 jle .L6 sub DWORD PTR [rbp-4], 1 mov DWORD PTR [rbp-4], 10 .L6: mov DWORD PTR [rbp-4], 20 nop pop rbp ret
作者回复: 不跳转就会继续顺序执行,也是会执行到 .L6 位置的代码的。
2022-08-31归属地:江苏2 - 白花风信子进程里面的挂起也是for(;;);叭
作者回复: 如果这里提到的“挂起”是指阻塞当前线程的话,可以使用 poll \ select \ semaphore 等方式哈。死循环并不是一个好的方式。
2021-12-18 - 友像 edi esi 对应的应该是 第一个参数 第二个参数吧 ~ 我记得有 6个还是7个寄存器可以用来传参
作者回复: 没错的,我们在第 05 讲有介绍这些内容哈。
2021-12-172 - chinandy老师:高优化等级怎么打开,在您给的那个网站上
作者回复: 可以直接在上方的 “Compiler options” 输入框里输入对应优化等级的参数,比如:-O2 \ -O3。
2021-12-14 - Geek_828b39将寄存器 rdx 中的值左移 v 位(值被扩展为 64 位); 老师,这个这么理解?
作者回复: 这里实际上是跟蓝框内的第一条汇编语句做的对比。第一条的 mov 指令仅把值 1 当做 32 位值放入到 edx 中;而后续程序在使用这个值生成“token”时,实际上是直接用 rdx 来访问的,因此实际上是在进行左移时同时被“扩展”为了 64 位值。同样的,后面进行按位与时,也是直接以 64 位值进行的。
2021-12-14