Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1172
  • 博文数量: 2
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2017-05-13 23:06
文章分类
文章存档

2017年(2)

我的朋友
最近访客

分类: C/C++

2017-05-16 23:17:27

    对于printf 函数,想必大家都不是很陌生。
    例如:
    int a = 3;
    printf("%d %d", a, a *= 2);
    输出的结果是6 6
    我想那些初学C语言的同学可能会有些疑问。为什么结果不是3 6?而是6 6?
    其实这个问题从表面上理解很简单,printf函数对参数的处理是从右向左进行的,因此输出的第一个值是6,而不是3。
    可是这种理解过于简单化了。大家有没有想过,为什么其对参数的处理是从右向左进行?为什么不是从左向右?从左向右不是更加符合我们的理解么?
    而且编译器对于代码的扫描是从左向右进行的,从左向右处理参数不是更加方便么?
    其实,不仅printf函数对参数的处理是从右向左,很多函数对参数都是从右向左处理的,C和C++的设计者当然也想过从左向右,只不过为了更加统一,更加方便的对一些变元数目不固定的函数处理,不得不从右向左处理罢了
我以前也不是很理解,前些天自学了栈,对这个问题有了些较为深层次的理解,特地写出来跟大家分享一下,当然,这也是我的第一篇技术博客,如果有什么不对的地方,还希望大家帮忙指出来

下面我用一个C语言的例子来解释这一问题:


点击(此处)折叠或打开

  1. #include <stdio.h>

  2. int Max(int const count, ...);//...代表的是函数参数个数不固定

  1. int Max(int const count, ...)//求最大值
  2. {
  3.     int *p = &count+1;//将存储的参数中第一个要比较的参数地址传给p
  4.     int max = *p;
  5.     int i;

  6.     for (i = 0; i < count; i++, p++)//循环比较大小
  7.         if (max < *p)
  8.             max = *p;

  9.     return max;
  10. }

  11. int main(void)
  12. {
  13.     printf ("%d\n", Max(4, 1, 3, 5, 7));//输出最大值

  14.     return 0;
  15. }

    函数调用输出的结果是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等。
    对于宏的使用,这里不再讨论。

    希望大家能在这篇文章里学到知识!也希望大家能帮我指出一些错误,以及改正的方法。谢谢大家!

阅读(270) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~