在实验中观察指针——C++ 函数参数的压栈顺序
前言
好久没写东西了,突发奇想,写写函数参数的压栈顺序
先看看这个问题
https://q.cnblogs.com/q/137133/
然后看我简化的代码,猜输出结果是多少?
#include<bits/stdc++.h>
using namespace std;
int main(){
int i=0;
printf("%d %d",i++,i--);
return 0;
}
根据++和--的特性,i++的时候数值不变,输出0,i--时i才加上1,输出1。
事实是这样吗?我在多台编译器上执行,输出的结果都是:
-1 0
栈
根据我之前写过的指针篇的内容,函数的局部变量保存在栈中,都是独立的,参数同样保存在栈中,才导致了swap函数改变函数参数必须使用指针。
那么,函数参数,在栈中是如何排列的呢?顺序?倒序?
我们写一个简短的代码,来实验一下。
#include<bits/stdc++.h>
using namespace std;
void test(int a,int b){
printf("a..%p, b..%p",&a,&b);
}
int main(){
int a,b;
test(a,b);
}
由于是地址,不同编译器的结果不同。但肯定的是,a比b大4。
如果多加几个变量进去,我们发现,地址的大小从大到小递减。
栈模型
图源:《征服C指针》

从这张图中可以看出,C语言中,参数是从后往前堆积在栈中的。这种处理方式的好处在于,无论有多少个参数,总能找到第一个参数的地址,这样就可以顺次找到后面的参数。否则,从后往前,就无法找到第一个参数,也无法实现可变长参数的功能。
例如在printf中,我们找到第一个参数的位置,例如"%d %s",就可以顺次解析后面的地址的参数,因为参数是连续在内存排列的。
问题解释
既然参数是从后往前放入栈中的,那么,我们就可以解释这个问题了。
#include<bits/stdc++.h>
using namespace std;
int main(){
int i=0;
printf("%d %d",i++,i--);
return 0;
}
开头的代码。如果编译成汇编语言进行执行,应该是这个样子(如果有错误请指正,手写的)
sub [i],1 ;i--
push [i]
add [i],1 ;i++
push [i]
push offset string "%d %d" ;"%d %d"
call dword ptr_printf ;调用printf
在汇编语言中,push是将参数压入栈的一个指令,由于这篇文章不是讲汇编的,大家看看就好。
因此,在推入栈的时候,先执行了i--,再执行i++,结果也当然是这样了。
在实验中观察指针——C++ 函数参数的压栈顺序的更多相关文章
- C、C++语言中参数的压栈顺序
要回答这个问题,就不得不谈一谈printf()函数,printf函数的原型是:printf(const char* format,-) 没错,它是一个不定参函数,那么我们在实际使用中是怎么样知道它的参 ...
- C语言函数入参压栈顺序为什么是从右向左?
看到有人提问到,在处理printf/cout时,压栈顺序是什么样的?大家都知道是从右往左,也就是说从右往左的计算,但是,这里的计算不等于输出. a++和++a的压栈的区别:在计算时,遇到a++会记录此 ...
- 函数调用过程中,函数参数的入栈顺序,why?
C语言函数参数入栈顺序为从右至左.具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数.通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底.除非知道参数个数,否则是无法通 ...
- C/C++多参数函数参数的计算顺序与压栈顺序
一.前言 今天在看Thinking in C++这本书时,书中的一个例子引起了我的注意,具体是使用了下面这句 单看这条语句的语义会发现仅仅是使用一个简单的string的substr函数将所得子串pus ...
- C语言函数参数压栈顺序为何是从右到左?(从左向右的话,碰到printf的会陷入死循环)
上学期学习了汇编语言,并在操作系统实验中使用了汇编+C语言混合编程,中间也了解了一些C语言与汇编语言的对应关系. 由于汇编语言是底层的编程语言,各种函数参数都要直接控制栈进行存取,在混合编程中,要用汇 ...
- C++ 二维数组(双重指针作为函数参数)
本文的学习内容参考:http://blog.csdn.net/yunyun1886358/article/details/5659851 http://blog.csdn.net/xudongdong ...
- Day8 函数指针做函数参数
课堂笔记 课程回顾 多态 virtual关键字 纯虚函数 virtual func() = 0; 提前布局vptr指针 面向接口编程 延迟绑定 多态的析构函数的虚函数. ...
- go语言基础之数组指针做函数参数
1.数组指针做函数参数 示例: package main //必须有个main包 import "fmt" //p指向实现数组a,它是指向数组,它是数组指针 //*p代表指针所指向 ...
- go语言基础之指针做函数参数用地址传递
1.指针做函数参数 示例: package main //必须有个main包 import "fmt" func swap(p1, p2 *int) { *p1, *p2 = *p ...
随机推荐
- AD设置过孔盖油
设置所有的过孔盖油 ==> 先选中一个过孔,然后根据对象类型查找相似器件,选中所有的过孔,然后勾选过孔盖油选项即可. 上述这种方法不是太好,每次修改完PCB后都要确认下新增的过孔是否已经过孔盖油 ...
- ASP.NET VS 调试提示:指定的端口正在使用中,建议切换到xxx之外并大于1024的端口
问题描述 使用 Visual Studio 开发 ASP.NET 网站的过程中,突然提示端口被占用: 解决方式 在启动项目上右键→属性,切换到 Web .直接修改服务器栏目里面的端口号,解决!
- Linux 磁盘分区和挂载
目录 Linux 磁盘分区和挂载 windows 下的分区 磁盘管理 相关命令 分区及挂载实现步骤 添加硬盘 分区步骤 步骤 挂载步骤 卸载分区步骤 补充: Linux 磁盘分区和挂载 windows ...
- CSS 常用颜色代号
常用颜色代号一览表:http://www.divcss5.com/html/h636.shtml #000000 #2F0000 #600030 #460046 #28004D ...
- Mybatis-Plus一键生成代码
Mybatis-Plus一键生成代码 一.闲言碎语 闲来无事看了看了MP的官网看到一键生成的代码更新了! 整个Ui风格都变了,遂决定瞅一眼新的代码生成器 官网地址~~ 二.引入依赖 新的代码生成只有在 ...
- 【LeetCode】1433. 检查一个字符串是否可以打破另一个字符串 Max Difference You Can Get From Changing an Integer
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 排序 日期 题目地址:https://leetcode ...
- java源码——计算立体图形的表面积和体积
计算球,圆柱,圆锥的表面积和体积. 利用接口实现. 上代码. Contants.java 常量存储类 package com.fuxuemingzhu.solidgraphics.contants; ...
- 【LeetCode】406. Queue Reconstruction by Height 解题报告(Python & C++ & Java)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【LeetCode】645. Set Mismatch 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Hash方法 直接计算 日期 题目地址: https ...
- 【LeetCode】732. My Calendar III解题报告
[LeetCode]732. My Calendar III解题报告 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/my-calendar ...