lieoo's blog

记一个基础错误

起因:有个小伙伴在群里问了这样一个问题:有会 C 语言的吗?

自告(zhuang)奋(bi)勇的说了一句:在!

代码如下:

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void){
int a=1;
printf("%d,%d,%d\n",a++,a,++a);
}

大概看了 2 秒,给出了答案:

2,2,3

结果惨遭打脸,一世英名毁于一题。

原因:

首先应该说明的是这段代码在不同的编译环境中结果是不一样的。

in Mac OS 10.13 GCC 4.2.1 (Xcode): 1,2,3

in Compile and Execute C Online (GNU GCC v7.1.1): 2,3,3

得知结果后,在想 What the FXXK 到底为什么,哪里错了。

错误总结:

第一:代码执行顺序

GCC 中 printf 函数的执行顺序是由右到左的。
直接运算明显错误,导致结果肯定不一致

第二:++i and i++

前自增运算符(++i)先加 1,再使用
后自增运算符(i++)先使用 i,执行语句代码后再加 1

第三:“计算”不等于“输出”

自增运算是要在整条语句结束以后才自加 1 的

答案:

想理解答案首先要理解编译顺序:
GCC v7.1.1 的编译器解释为:

从右往左计算:

  1. i++ 等于 1(整条语句执行完毕之后才会执行 +1 操作)
  2. i 在这里还是等于 1
  3. ++i 等于 2
  4. 执行 i++ 操作 i 等于3

所以结果 2,3,3 是这样得出来的。

在 GCC 4.2.1 中

使用 GCC -o 命令来编译,直接报错 Unsequenced modification and access to 'a' 理解为中文的大概意思就是 在一个表达式中改变了变量的值,又在同一个表达式的另一个地方使用了同一个变量的值,这样是不被允许的导致直接编译通过不了。

在 Xcode 中

在 Xcode 编译却被通过,只不过结果和上述不一致的(手动笑脸)。

总结

对于这种代码,不同编译器结果会不一样,避免使用才是真正的答案,除人为强行的规范代码,对于这些底层编译原理还要理解和学习。

这篇文章从解决问题、简单理解原理到写出这篇博客,耗时三小时,现在是深夜 3 点钟。

有收获的感觉好爽。