深入 C 语言和程序运行原理
于航
PayPal 技术专家
21121 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
深入 C 语言和程序运行原理
15
15
1.0x
00:00/00:00
登录|注册

03|计算单元:运算符是如何工作的?

提前推算变量取值,省去运行时类型转换过程
减少对栈内存的使用
sizeof 在编译时求值,强制类型转换对应不同指令处理方式
取地址运算符对应 lea 指令,解引用运算符对应 mov 指令
使用 testcmp 指令判断操作数状态,进行数值转换
直接对应到汇编指令
sizeof 在编译时求值,强制类型转换对应不同指令处理方式
取地址运算符对应 lea 指令,解引用运算符对应 mov 指令
使用 testcmp 指令判断操作数状态,进行数值转换
直接对应到汇编指令
编译器如何实现三元运算符 "?:"
高编译优化等级下的实现方式
其他运算符
成员访问运算符
逻辑运算符
算数、关系、位、赋值运算符
其他运算符
成员访问运算符
逻辑运算符
算数、关系、位、赋值运算符
思考题
性能优化
实现细节
运算符分类
C 语言中运算符的编译器实现

该思维导图由 AI 生成,仅供参考

你好,我是于航。
运算符(operator)、表达式(expression)和语句(statement)是组成 C 程序的三个最基本的语法结构。在 C 语言中,这三种概念之间一般呈“包含”关系,即表达式中通常含有运算符,而语句中也可以包含有表达式。最终,众多的语句便组成了一个完整的 C 程序。
可见,一个完整的 C 程序是由不同粒度的语法单元自下而上一层层构建出来的。而在这层语法形式之下,运算符、表达式和语句究竟是怎样被编译,并通过机器指令表达的呢?
作为 C 语言中用于提供计算能力的核心语法结构,运算符在支持应用核心功能的构建过程中,起着不可或缺的作用。那么这一讲,我们就先来看看,C 语言中的运算符究竟是如何被编译器实现的。

C 运算符的分类

在目前最新的 C17 标准中,C 语言一共有 48 个运算符。按照这些运算符功能的不同,我们可以将它们分为七类(分类方式并不唯一),如下表所示:
这七类运算符在功能上均有所不同,因此,使用机器指令进行表达的具体方式和复杂程度也不同。其中,算数、关系、位与赋值运算符由于功能较为基础,可以与某些机器指令一一对应,因此我们会放在一起进行介绍。而逻辑运算符、成员访问运算符及其他运算符,由于实现相对复杂,我会分开讲解。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

C语言中的运算符在编译器中的实现方式是程序员们需要了解的重要技术细节。本文详细介绍了C语言中的运算符分类及其在编译器中的实现方式。根据最新的C17标准,C语言共有48个运算符,包括算数、关系、位、赋值等七类。文章通过示例代码和对应的汇编代码,详细介绍了加法、大于号和按位或运算符的实现方式,以及相关的汇编指令。此外,还介绍了FLAGS寄存器和标志位的概念,以及在比较指令执行后引起的CPU状态变化。在高编译优化等级下,编译器实现这些运算符的基本逻辑仍然不变。文章还介绍了逻辑与运算符的实现方式,包括条件跳转指令和高优化等级下的实现方式,以及成员访问运算符的实现细节。总的来说,本文通过深入的技术讲解,帮助读者了解了C语言中运算符在编译器中的实现方式,为读者提供了深入的技术知识。文章还介绍了逻辑与运算符的实现方式,包括条件跳转指令和高优化等级下的实现方式,以及成员访问运算符的实现细节。总的来说,本文通过深入的技术讲解,帮助读者了解了C语言中运算符在编译器中的实现方式,为读者提供了深入的技术知识。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(20)

  • 最新
  • 精选
  • 青鸟飞鱼
    问一个比较困惑的问题,学习c语言,真的要了解汇编吗

    作者回复: 其实对于日常开发来说,不了解汇编并不会有太大的影响,因为这也是 C 语言被创造出来的目的之一。但计算机知识其实是成体系的,如果你想要“知其然,并知其所以然”,那了解汇编是一个必要的过程。

    2021-12-12
    15
  • =
    例如b = (a==3?3:2)。 三目运算符的汇编实现中,采用了cmp指令来比较a与3的大小,接着使用cmov指令根据cmp后的FLAGS寄存器的状态位的值,来决定b的值是3还是2。

    作者回复: 没错!关于 cmove 指令的更多细节我们会在第 18 讲再深入讨论。

    2021-12-11
    5
  • 无名氏
    请教下老师,这个汇编和c语言颜色对应的图是咋生成的😄

    作者回复: 可以参考这里哈:https://godbolt.org/

    2022-05-09
    3
  • ppd0705
    使用 `gcc -S` 得到的汇编代码风格不一样,请问要如何得到文章中的汇编代码风格呢?

    作者回复: 可以尝试用 `objdump -M intel -d ./foo` 这个命令哈。

    2022-01-28
    2
    3
  • Nuyoah
    mov edx, DWORD PTR [rbp-8] mov eax, DWORD PTR [rbp-4] cmp edx, eax cmovge eax, edx mov DWORD PTR [rbp-12], eax 自己理解是cmovage对应? cmp用来比较两个操作数的大小 最后的mov汇编指令将满足条件的操作数以32位存入寄存器相应位置

    作者回复: 没错哈!

    2021-12-26
    2
  • 阿锭啊阿滨啊
    L3问题:为什么还要and 1呢?前面不是赋值要么0要么1了吗?还会是其他值吗?

    作者回复: 想想 `bool` 这个关键字?

    2022-01-09
    3
    1
  • 白凤凰
    L3的思考题,为什么我的执行是这个样子的?没有and哪句指令。 .L3: mov BYTE PTR [rbp-1], al movzx eax, BYTE PTR [rbp-1] mov esi, eax mov edi, OFFSET FLAT:.LC0 mov eax, 0 call printf

    作者回复: 是用的同一段 C 代码吗?具体使用的编译器和环境是怎样的呢?如果方便的话,也可以完整地回复一下汇编代码哈。

    2021-12-22
    1
  • 没有軒的筝
    “程序会按顺序将位于栈内存中的变量 x 和 y 的值与数值 0 进行比较。若其中的某个比较结果相等,程序执行将会直接跳转到标签 “.L2” 的所在位置“,这句话是什么意思的?是变量x和y的值分别与0进行比较吗?还有“某个比较结果相等”是变量x和变量y分别与0比较后的两个结果吗?

    作者回复: 实际上就同汇编代码展示的那样,rbp-20 与 rbp-24 位置上分别存放着变量 x 与 y 的值。而对应的两行 cmp 指令执行时,会分别将这两个值与数值 0 进行比较,当其中任意一个变量的值与 0 相等时,则程序紧接着会执行标签 .L2 处的指令。

    2022-03-15
  • je不是相等才跳转吗,结果相等,ZF会置1吧,上面说je判断ZF是否为0,若为0则跳转

    作者回复: 感谢指正!

    2022-03-09
  • zxk
    逻辑运算符优化后的那段汇编: test edi, edi ; edi <- x. setne al test esi, esi ; esi <- y. setne sil movzx esi, sil and esi, eax 为什么要使用 movzx 进行零扩展呢,直接 and al sil 或者 and esi eax 不是可以节省一条指令么?

    作者回复: 因为我们不能直接假定 sil 的高位字节都是 0,所以需要用零扩展来“扩大”值的宽度。而之所以要用 esi 寄存器而不是 sil 的一个可能原因是:通常来说,机器指令在以“自然大小”为长度的寄存器(这里就是 esi)上进行相应的数据操作,效率是最高的。因此,即使少执行一条指令,也并不见得开销就一定最小。当然,这里也只是猜测,实际上只是编译器的一种实现上的选择。

    2022-01-16
收起评论
显示
设置
留言
20
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部