最近我在看uboot的源码,里面好多if()逻辑判断的条件是直接使用了某个函数的函数调用表达式而非先将函数调用的返回值写到一个临时变量中使用这个临时变量参与判断。
于是,从C语言的角度(而非汇编代码的通用寄存器的角度)思考,为什么要这样写,这样写的好处有那些?
首先我们要理解,c语言是支持if条件判断中直接使用函数调用表达式的。从C语言的角度看,是没有定义一个临时变量,将函数调用的结果写到这个“隐藏临时变量”中的。C语言是一种高级语言,也就是更加符合人的思维,c语言支持这样写,说白了主要还是编译器比较“牛逼”它支持。
不使用中间变量接收函数调用返回值,而是直接使用函数调用表达式的好处有那些?
(1)代码更加简洁,减少冗余变量。达到同样的目的,直接使用函数调用表达式的方式,省略了定义临时栈变量,给栈变量写函数调用返回值,主函数执行完毕释放栈变量等操纵。代码更简洁(代码行更少,也不用定义栈变量、释放栈变量等操纵)。
(2)直接使用函数调用表达式能够降低出错概率。如果代码很长,中间变量的值如果不小心被写了“第二次”而不会被察觉的话,后面的条件判断就会出错。而直接使用函数表达式则是当前的返回值,不会出错。
(3)提高代码可读性(逻辑更加集中),直接使用函数调用表达式更加直接,如果使用中间变量,还需要去前面查看这个变量是如果被函数调用返回值赋值的。
(4)直接使用函数调用表达式的方式非常适合主函数中函数调用的返回值只被“调用一次”的情况。我在这里的意思是函数调用返回值只被“读一次”的情况。试想一下,如果函数被调用的返回值写到了一个临时变量中,但是这个变量在后面只被用了一次就再也没有用到第二次,那这个时候使用临时变量的方式就比较浪费了,这个时候就可以直接使用函数调用的方式利用其返回值。
什么时候适合使用中间变量,而不适合直接使用函数调用表达式。
(1)与上面第4条相对。如果函数调用的返回值在主函数中被读多次,这个时候就适合使用中间变量,而不适合使用函数调用表达式。因为函数调用一次需要的开销更大,尤其是函数代码很长的时候。而多次读中间变量的开销要小很多。
(2)对于rand()这类有“副作用”的函数,每次调用的返回值都不相同的情况。这种情况不是“不适合”问题而是“不能使用”,使用后会出错。
(3)需要代码调试观察返回值的情况,因为直接使用函数调用无法将返回值添加到watch窗口中观察,如果代码需要调试,这个时候就需要“显示”使用中间变量接收函数调用返回值,观察返回值的具体数值,调试完后可以再将中间变量删除掉,改用“直接使用函数调用”的情况。
注意,考虑问题的时候千万别“汇编”、“C语言”混在一起,c语言就从c语言的角度思考为什么可以这样,千万别c语言中有考虑汇编的一些只是用法,因为c编译器只能将C语言编译成汇编(也就是C编译器只支持.c源文件,不识别.S或.s源文件)。我当时以为直接函数调用的“隐藏变量”是存在ARM通用寄存器例如r0中的,实际上这种想法是错误的,就反了混在一起考虑问题的毛病。我还有一个想法是定义了一个隐藏的栈变量,将函数调用的返回值写到这个隐藏的不可知的栈临时变量中,这种想法也是错误的,因为这个隐藏栈变量根本不存在,C编译器是不是这样解析代码的。
最后,思考一下C语言相对汇编代码为什么说他是一种高级语言,到底高级在哪里,c语言是如何更接近人类的自然语言的,它隐藏了汇编语言的哪些内容,让程序员不必考虑甚至不知道哪些内容。
附加:如果一个数组成员的下标是类似array[func(x,y)]这种方式,c高级语言也是支持的,并且也是先调用内部函数func(x, y)然后将返回值作为下标或者索引值与数组名共同组成了数组某一个成员。
7392

被折叠的 条评论
为什么被折叠?



