简单好用的 ++,--
说到自增 (++)\ 自减(--) 运算符, 小伙伴们应该都不会陌生, 在很多编程语言的代码中, 都经常出现它们的身影.
比如常用的 for 语句
- for (int i = 0; i <n; i++) {
- // TODO
- }
比如经典的一行代码实现字符串拷贝
- // 将 src 的内容拷贝至 dest
- void strcpy(char *dest, char *src) {
- while (*dest++ = *src++);
- }
- int main() {
- char s1[10], *s2 = "xmg_mj";
- strcpy(s1, s2);
- printf("%s", s1); // xmg_mj
- return 0;
- }
使用得当的话, 自增 (++)\ 自减(--) 运算符的确可以让代码简洁又优雅.
但是
2 大热门编程语言 Swift,Python 并不支持自增 (++), 自减(--) 运算符, 这是为什么呢?
这里先给出几个参考链接, 有兴趣的小伙伴可以自行去阅读一下:
Swift 之父 Chris Lattner 的说明
从 Swift3 开始不支持 ++,--
来自 Stack Overflow 的一个问答
- Why are there no ++ and -- operators in Python?
- https://stackoverflow.com/questions/3654830
来自 Google 研发总监(Director of Research)Peter Norvig 的观点
- The Python IAQ: Infrequently Answered Questions
- http://norvig.com/python-iaq.html
这里只列出几个显而易见的理由
有了强大又简洁的 for-in,for 语句中可以完全不需要 ++,--
- // C++
- for (int i = 0; i < 5; i++) {
- cout << i << endl;
- }
- // Swift
- for i in 0..<5 {
- println(i)
- }
- // Python
- for i in range(5):
- print(i)
尽管 while (*d++ = *s++); 看起来似乎简单而优雅, 但对于初学者来说绝非简单, 会增加学习成本. 而 Swift,Python 更倾向于希望任何人都能快速上手这门编程语言.
当混合使用前缀和后缀的 ++,-- 时
会降低代码的可读性, 比如 while (n++> --k), 经验丰富的程序员也必须停下来思考一下代码的具体含义是什么
运行结果可能会有不确定性
运行结果的不确定性
下面列出 2 段代码, 变量 b 的结果是什么呢?(值得一提的是: 实际开发中我们并不会这么写, 这里把它列出来仅仅是为了讨论一些技术细节)
- int a, b;
- // 第 1 段代码
- a = 1;
- b = a++ + ++a + a++ + ++a;
- // 第 2 段代码
- a = 1;
- b = a++ + a++ + a++ + a++;
实际上, 上面的 C 语言代码在 MSVC,MinGW 编译器下得出的结果是不完全一致的
MSVC: 微软出品
MinGW:GNU 出品(可以理解为 Windows 版本的 GCC)
第 1 段代码
结果一致, 符合绝大部分人的预期, 所以就不展开讨论了
- a = 1;
- b = a++ + ++a + a++ + ++a;
- // MSVC:b = 1 + 3 + 3 + 5 = 12
- // MinGW:b = 1 + 3 + 3 + 5 = 12
第 2 段代码
结果不一致
MSVC 的结果是 1 + 1 + 1 + 1 = 4
MinGW 的结果是 1 + 2 + 3 + 4 = 10
- a = 1;
- b = a++ + a++ + a++ + a++;
- // MSVC:b = 1 + 1 + 1 + 1 = 4
- // MinGW:b = 1 + 2 + 3 + 4 = 10
你可能好奇: 你怎么知道 MinGW 的计算过程是 1 + 2 + 3 + 4 呢? 根据最终结果 10 反推回去猜出来的么? NO! 如果是这样做的话, 那就有点侮辱了程序员这个职业了.
像这种不太容易从表面去理解的代码, 你若想知道它的真正本质, 那就要搬出强有力且精准的武器了, 它就是汇编语言(Assembly Language).
简单说明一下使用汇编语言的理由:
众所周知, C 语言代码最终都会被编译为机器语言代码(也叫做机器指令, 只由 0 和 1 组成)
那通过研究最终的机器指令来探索 C 语言代码的本质? 由于机器指令极其晦涩难懂, 因此, 对一般人来说, 这并不是一种高效的办法
最佳的办法是: 研究一下介于 C 语言, 机器语言之间的汇编语言代码
C 语言 → 汇编语言 ↔ 机器语言
汇编语言代码比机器指令可读性高很多
每一条机器指令都有与之对应的汇编语言代码
因此, 你研究汇编语言代码, 基本就等同于研究机器指令, 可读性 + 精准性兼具
看看 MSVC 环境下的汇编代码
红框代码: 将 4 个 a 相加的结果赋值给 b, 由于 a 的初始值是 1, 所以 b = 1 + 1 + 1 + 1 = 4
绿框代码: 让 a 执行 4 次自增 1 的操作, 相当于执行 4 次 a += 1
看看 MinGW 环境下的汇编代码
为了保证能基本看懂这段汇编代码, 建议你可以理解为 [rbp-0x4] 代表变量 a,[rbp-0x8]代表变量 b
绿框代码: 让 a 执行自增 1 的操作, 相当于执行 a += 1
红框代码: 将 a 每次自增 1 之前的值累加起来, 最后赋值给 b
可以看到, 绿框, 红框代码是交替执行的, 所以最终 b = 1 + 2 + 3 + 4 = 10
最后 2 段代码
最后再放 2 段代码出来, 在 MSVC 和 MinGW 下的结果也是不一致的
- a = 1;
- b = ++a + ++a + ++a + ++a;
- // MSVC:b = 5 + 5 + 5 + 5 = 20
- // MinGW: b = 3 + 3 + 4 + 5 = 15
- a = 1;
- b = ++a + ++a + a++ + a++;
- // MSVC:b = 2 + 3 + 3 + 4 = 12
- // MinGW:b = 3 + 3 + 3 + 4 = 13
根据前面的一些讲解, 相信你现在可以推断出 MSVC 的结果了.
但 MinGW 的结果可能还是会让人感觉到奇怪: 它其实是先让最前面的 2 个 ++a 执行 a 自增 1 的操作, 后面的 2 个 ++a\a++ 就照常处理, 所以最终 b = 3 + 3 + ...
好了, 就此打住, 建议不要去纠结这些细节了, 因为本来就不推荐这种写法. 你只需要知道: 多个前缀, 后缀的自增自减一起使用时, 结果具有不确定性.
总的来说,++,-- 是把双刃剑, 再者, 它并非是编码过程中必不可缺的, 所以被 Swift,Python 抛弃也是正常的事.
关于汇编
经常看到有人说: 汇编语言都是上古时期的编程语言了, 没啥用, 甚至还有人说 C\C++ 这么古老的语言, 没有任何学习价值. 我个人并不赞同这些观点. 掌握好汇编, 可以更好地了解代码的本质, 扫除一些基本的知识误区.
因为时间和篇幅的关系, 这篇文章并没有详细解释每一句汇编代码的作用. 如果你对汇编感兴趣, 可以参考以下图片
之前有在 B 站上传一些汇编教程, 有需要的小伙伴可以向公众号发送汇编两字, 获取教程地址
最后的思考题
最后留一道思考题, 可以将思考的结果直接留言评论
不是说 Python 不支持自增 (++)\ 自减(--) 运算符么, 为什么下面的 Python 代码能运行成功呢?
- a = 10
- b = ++a
- c = a++ + ++a
如果你特别希望我写点什么方面的内容, 也可以留言建议, 谢谢
来源: https://www.cnblogs.com/mjios/p/12674242.html