对于printf 函数,想必大家都不是很陌生。
例如:
int a = 3;
printf("%d %d", a, a *= 2);
输出的结果是6 6
我想那些初学C语言的同学可能会有些疑问。为什么结果不是3 6?而是6 6?
其实这个问题从表面上理解很简单,printf函数对参数的处理是从右向左进行的,因此输出的第一个值是6,而不是3。
可是这种理解过于简单化了。大家有没有想过,为什么其对参数的处理是从右向左进行?为什么不是从左向右?从左向右不是更加符合我们的理解么?
而且编译器对于代码的扫描是从左向右进行的,从左向右处理参数不是更加方便么?
其实,不仅printf函数对参数的处理是从右向左,很多函数对参数都是从右向左处理的,C和C++的设计者当然也想过从左向右,只不过为了更加统一,更加方便的对一些变元数目不固定的函数处理,不得不从右向左处理罢了。
我以前也不是很理解,前些天自学了栈,对这个问题有了些较为深层次的理解,特地写出来跟大家分享一下,当然,这也是我的第一篇技术博客,如果有什么不对的地方,还希望大家帮忙指出来。
下面我用一个C语言的例子来解释这一问题:
-
#include <stdio.h>
-
-
int Max(int const count, ...);//...代表的是函数参数个数不固定
-
-
int Max(int const count, ...)//求最大值
-
{
-
int *p = &count+1;//将存储的参数中第一个要比较的参数地址传给p
-
int max = *p;
-
int i;
-
-
for (i = 0; i < count; i++, p++)//循环比较大小
-
if (max < *p)
-
max = *p;
-
-
return max;
-
}
-
-
int main(void)
-
{
-
printf ("%d\n", Max(4, 1, 3, 5, 7));//输出最大值
-
-
return 0;
-
}
函数调用输出的结果是7。
下面我们看一下在函数调用的时候,内存里的堆栈情况是如何的:
p
|
max
|
i
|
返回的地址
|
4(count)
|
1
|
3
|
5
|
7
|
如上图所示,编译器按照从右向左的方式将Max的所有参数压到栈空间里,然后通过p指针指向count的高一个单位的空间来找到所要判断的参数。在通过循环找到所有参数中的最大值,并返回结果。计算机为什么能找到count所在的空间?那是因为计算机记录了函数的返回地址。通过返回地址,计算机可以在不知道参数个数的情况下找到其头部,并且进行运算。
假设编译器按照从左向右的顺序将Max的参数压入栈中,那么计算机在不知道参数个数的情况下找到count,那是不可能的。这就像是又让马儿跑,又想马儿不吃草一样。想知道参数个数需要找到count,而想要找到count又必须知道参数个数。这是矛盾的。因此,函数从右向左对函数进行处理的。
不过为了使访问变长变元的函数参数更容易,C++中提供了解决变长参数问题的宏。例如va_list, va_start, va_arg, va_end等。
对于宏的使用,这里不再讨论。
希望大家能在这篇文章里学到知识!也希望大家能帮我指出一些错误,以及改正的方法。谢谢大家!
阅读(1196) | 评论(0) | 转发(0) |