IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C语言】printf函数参数压栈问题 -> 正文阅读

[C++知识库]【C语言】printf函数参数压栈问题

先看一个例题:

#include

int main(){
 
 int a=1; 
 printf("%d, %d, %d\n", ++a, a, a++);
 
 return 0;
}

大家可以思考一下?输出结果是什么?
2,2,2?
3,2,1?
3,3,1?

正确输出结果是:331

分析:

1、++a表示先把a+1,然后再用;a++表示先用a后把a+1,

2、printf()语句多个参数的执行顺序,从右往左

3、从右往左:a++,先a=1,然后a+1,这时a变成2,++a,a先加1,a=3,打印出来:3,3,1。中间的a是++a之后的值即是3。

编译的时候从右向左,输出的时候从左往右。

为什么参数从右至左压栈?
(1)可以动态变化参数个数。通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底。这样的话,除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反。
(2)更符合习惯。 采用这种顺序,是为了让程序员在使用C/C++的“函数参数长度可变”这个特性时更方便。
什么是“函数参数长度可变”?printf就是一个例子,它的参数的个数就是可变的。比如,printf(“%d %d %d”,1,2,3),在采用从右向左的参数入栈顺序时,参数出栈顺序时"%d %d %d",1,2,3。如果采用从左向右的入栈顺序,则出栈顺序变为3,2,1,“%d %d %d”,这样就不能提前知道会有多少个参数

#include<stdio.h>

int main(){
 
 int a;
 a=1;   printf("%d %d\n",a,a++);
 a=1;   printf("%d %d\n",a++,a);
 a=1;   printf("%d %d %d\n",a,a++,a);
 a=1;   printf("%d %d %d %d\n",a,++a,a++,a);
 
 return 0;
}

注:只要是输出a,一定是加完之后输出的a

输出结果:
2 1
1 2
2 1 2
3 3 1 3

底层原理:
主要是因为栈(压栈),栈是先进后出,后进先出。
C函数的参数压栈顺序是从右到左,printf和scanf函数都是,采用压栈从右到左的原因如下:
printf函数的原型是:

printf(const char* format,…)

它是一个不定参函数,我们在实际使用中是怎么样知道它的参数个数呢?这就要靠format了,编译器通过format中的%占位符的个数来确定参数的个数。

现在我们假设参数的压栈顺序是从左到右的,这时,函数调用的时候,format最先进栈,之后是各个参数进栈,最后pc进栈,此时,由于format先进栈了,上面压着未知个数的参数,想要知道参数的个数,必须找到format,而要找到format,必须要知道参数的个数,这样就陷入了一个无法求解的死循环了。

而如果把参数从右到左压栈,函数调用时,先把若干个参数都压入栈中,再压format,最后压pc,这样一来,栈顶指针加2便找到了format,通过format中的%占位符,取得后面参数的个数,从而正确取得所有参数。

所以,如果不存在这种不定参的函数,则参数的压栈顺序无论是从左到右还是从右到左都是没关系的。

函数有多个参数时计算总得有个顺序吧?不是从左至右,就是从右至左,抑或从中间向两边;一句话选定一个顺序后就“大家都这么办”,总不能有些函数从左至右,有些函数从右至左,那编译器就太难做了。当初选择从右至左肯定是这样有好多方便之处,比如printf中的参数表,由于C是基于栈操作的,栈又是后进先出的,从右至左计算压栈,然后按弹出顺序输出到屏幕上刚好顺应了大多数文本从左至右的习惯,很是方便;若从左至右计算压栈,处理就没有这么方便了。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:22:52  更:2022-05-09 12:24:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 21:41:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码