staic 变量使用的相关问题
笔者最近看《C与指针》这本书,发现了许多从前学习时没有遇见的有趣问题。
最让笔者震惊的是第五章5.8习题中第二题,让笔者又从头认真学习了一遍C语言的 static 变量。
代码
int fun(){
static int count = 1;
return ++count;
}
int main(){
int answer ;
answer = fun() - fun() * fun() ;
printf("%d\n",answer);
return 0;
}
刚开始,笔者用一向的惯性思维思考这个问题。
- 首先,从主函数进入,answer 的值未知,执行到主函数第二条语句,answer 被赋值为 fun() + fun() * fun() ,毫无疑问,第一个肯定执行优先级高的乘法。 因此,进入左数第二个 fun() 函数内部。
- 其次,进入fun() 内部,因为 count 是静态变量,++count 的意义是先加再return,因此执行完return 语句之后 count 的值应该是2;
- 接着,左数第二个fun() 的值是2,接下来进入左数第三个 fun() 函数内部。 因此 count 被重现赋值为“1”,因此返回值应该与左数第二个 fun() 返回值相同为2;
- 左数第一个同理,返回值为2.
因此笔者自信地写下了answer 的值为 -2.
结果打开vim 编辑之后,发现事情没有这么简单。。。
是的,输出的结果是 -10。 嗯??????
身为一位新时代的年轻人,不禁想问一句,“什么鬼操作???”
不如吃茶去。。。
脑子一机灵,不如化简?
不错不错,根据笔者的想法,将源代码的主函数化为:
int answer;
int a = fun();
//printf("a %d\n", a);
int b = fun();
//printf("b %d\n", b);
//printf("mul %d\n", a*b);
answer= fun() - a * b;
printf("%d\n", answer);
vim 执行完之后结果,恰好是笔者写的 -2 。当然,这个结果是完全错误的。。。
到底问题出在哪了呢?
- 问题在这,static 有点特殊,第一次进入fun 函数时,count 被赋值为1, 接着 return 语句中,count 自加1,这时, count 的值为2。
- 接着执行进入第二个 fun 时,这时 static int count = 1 并没有起到赋值的作用,编译器直接忽略这一语句。执行了 return 语句,这时 count 的值为3。
- 同理,第三个 fun 执行完之后,count 的值可得到为4。
那么?答案不是 4-2*3 = -2 么?不是,事情没有那么简单。。。
继续继续,我们认真观察这一天语句:
answer = fun() - fun() * fun() ;
必须要清楚的是,fun() 不是一个变量,而是一个返回值。fun() 函数地址是一定的,因此其实结果是 answer = 4 - 4*4 ,这样结果就是 -10了么。 是这样么???
想知道我们的推理是否正确,不如将 “-” 改为 “+”。
因此我们将源代码这条语句改为:
answer = fun() + fun() * fun() ;
如果按照我们的推理,得到的结果应该是20 才对。
14??? 不按常量出牌啊老铁。
证明我们的想法是完全错误的。。。
不过,我们已经将函数的返回值与变量值之间的关系区分开了。这时看到《C与指针》上的一段话:
什么意思呢?
不如让我们抛弃算数逻辑的先后顺序。 从左向右执行下去。
- 首先,执行左边第一个 fun() 函数,这时 count 返回2,第一个 fun() 返回了2.
- 接着执行第二个 fun() ,这时 count 为3, fun()
的返回值为3. - 最后执行最后一个 fun() ,同理,fun() 的返回值为4。
这样的话,我们再将得到的返回值进行逻辑运算。
answer = fun() - fun() * fun() ;
// 相当于 answer = 2 - 3 * 4 自然就是 -10
answer = fun() + fun() * fun();
// 相当于 answer = 2 + 3 * 4 自然就是 14
这样我们就清楚了。
总结
我们可以得到这么一条结论:
当语句中存在函数时,会优先执行函数的操作,而后进行运算符的执行。
其实这么说有些果断,片面。 因为当了解数据结构中,运算的实现原理之后,就会明白为什么笔者现在会这么说。 大致来说,运算的实现是又两个“栈”实现的,一个“运算符储存栈”,一个“变量储存栈”。关于这个问题的具体详解,笔者后面会讲到。