c/c++的函数参数压栈顺序
整理日:2015年3月18日
为了这句话丢了很多次人.无所谓了,反正咱脸皮厚.
总结一下
编译出来的c/c++程序的参数压栈顺序只和编译器相关!
下面列举了一些常见的编译器的调用约定
VC6
调用约定 | 堆栈清除 | 参数传递 |
---|---|---|
__cdecl | 调用者 | 从右到左,通过堆栈传递 |
__stdcall | 函数体 | 从右到左,通过堆栈传递 |
__fastcall | 函数体 | 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈 |
thiscall | 函数体 | this指针默认通过ECX传递,其它参数从右到左入栈 |
__cdecl是CC++的默认调用约定; VC的调用约定中并没有thiscall这个关键字,它是类成员函数默认调用约定;
CC++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改;
默认调用约定一般能够通过编译器设置进行更改,如果你的代码依赖于调用约定,请明确指出需要使用的调用约定;
C++Builder6
调用约定 | 堆栈清除 | 参数传递 |
---|---|---|
__cdecl | 调用者 | 从右到左,通过堆栈传递(与CC++默认调用约定兼容) |
__stdcall | 函数体 | 从右到左,通过堆栈传递(与VC中的__stdcall兼容) |
__fastcall | 函数体 | 从左到右,优先使用寄存器(EAX,EDX,ECX),然后使用堆栈 (兼容Delphi的register) |
msfastcall | 函数体 | 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈(兼容VC的__fastcall) |
__pascal | 函数体 | 从左到右,通过堆栈传递 |
由于能力和资源有限,只能找到这些东西,主要的差异体现在fastcall上面,vc是前两个参数放入寄存器,后面的压栈,bcb是前3哥参数使用寄存器, 更有变态的,一个朋友朋友说有的参数超过7个以后前5个从左到右传递,后面的从右到走,上面说的不可不信,不可全信.
如何确定你的编译采用的那种顺序那?
#include <stdio.h>
int f(int i,int j,int k);
int main()
{
static int i=0;
f(i++,i++,i++);
return 0;
}
int f(int i,int j,int k)
{
int l;
int g;
printf("k=%d:[%x] ",k,&k);
printf("j=%d:[%x] ",j,&j);
printf("i=%d:[%x] ",i,&i);
printf("\_\_\_\_\_\_\_\_\_\__ ");
printf("l:%x ",&l);
printf("g:%x ",&g);
}
看看k->i的地址的增长顺序和l->g的顺序是否相同,如果相同则是从右到左,否则从左到右.
PS
本来通过打印参数的值来判断那个先入栈,结果被一个朋友批评了,
他说:压栈顺序和参数计算顺序不是一回事,所以还是看地址更有保证.
看过的朋友当作笑谈吧。
曾经看到一篇文章上面说:c/c++参数压栈顺序是从右到左,pascal参数压栈是从左到右.
注意点
- 尽量不要在函数参数中运行象pop之类的参数
- 32bit和64bit同一源码时要注意
c/c++的函数参数压栈顺序的更多相关文章
- C语言函数参数压栈顺序为何是从右到左?(从左向右的话,碰到printf的会陷入死循环)
上学期学习了汇编语言,并在操作系统实验中使用了汇编+C语言混合编程,中间也了解了一些C语言与汇编语言的对应关系. 由于汇编语言是底层的编程语言,各种函数参数都要直接控制栈进行存取,在混合编程中,要用汇 ...
- C/C++多参数函数参数的计算顺序与压栈顺序
一.前言 今天在看Thinking in C++这本书时,书中的一个例子引起了我的注意,具体是使用了下面这句 单看这条语句的语义会发现仅仅是使用一个简单的string的substr函数将所得子串pus ...
- c语言中函数参数入栈的顺序是什么?为什么
看到面试题C语言中函数参数的入栈顺序如何? 自己不知道,边上网找资料.下面是详细解释 #include <stdio.h> void foo(int x, int y, int z){ ...
- c++参数入栈顺序和参数计算顺序
关于 本文涉及到代码,演示环境为:win10 + VS2017 ,ubuntu+clang clang版本: 参数入栈顺序 顺序 几种常见的函数参数入栈顺序,还有两种就不介绍了(__clrcall._ ...
- 在实验中观察指针——C++ 函数参数的压栈顺序
前言 好久没写东西了,突发奇想,写写函数参数的压栈顺序 先看看这个问题 https://q.cnblogs.com/q/137133/ 然后看我简化的代码,猜输出结果是多少? #include< ...
- C语言函数入参压栈顺序为什么是从右向左?
看到有人提问到,在处理printf/cout时,压栈顺序是什么样的?大家都知道是从右往左,也就是说从右往左的计算,但是,这里的计算不等于输出. a++和++a的压栈的区别:在计算时,遇到a++会记录此 ...
- C、C++语言中参数的压栈顺序
要回答这个问题,就不得不谈一谈printf()函数,printf函数的原型是:printf(const char* format,-) 没错,它是一个不定参函数,那么我们在实际使用中是怎么样知道它的参 ...
- 测试当前C环境的栈帧增长方向以及传递参数时的压栈顺序
前文链接:上次由于一个很常见的printf-bug(下文有提及)引发了我对栈的思考,并写下了一点总结.这次就尝试对不同的C环境进行实践,检测其传递参数的一些性质. 这是今天写的检查C环境的一段程序.能 ...
- C/C++---printf/cout 从右至左压栈顺序实例详解
__cdecl压栈顺序实例 明白计算:计算是从右到左计算的 栈和寄存器变量:x++,是将计算结果存放到栈空间,最后是要出栈的:而++x和x是将计算结果直接存放到某个寄存器变量中(是同一个),所以计算完 ...
随机推荐
- Unicode与UTF-8互转(C语言实现)
1. 基础 1.1 ASCII码 我们知道, 在计算机内部, 所有的信息最终都表示为一个二进制的字符串. 每一个二进制 位(bit)有0和1两种状态, 因此八个二进制位就可以组合出 256种状态, 这 ...
- Java程序猿学习C++之字符串
#include <iostream> #include <string.h> using namespace std; int my_len(const char *str) ...
- OpenFileDialog
打开一个文件 private void button1_Click(object sender, EventArgs e) { openFile ...
- [互联网面试笔试汇总C/C++-7] 寻找两个链表的第一个交点-微策略
题目:有两个链表,找出他们的第一个交点,要求每个链表只能遍历一次,可以对链表进行任何操作,空间O(1). 思路: 这个题目刚开始看觉得要遍历一次有点困难,但是仔细一想,人家告诉说可以对链表进行任何操作 ...
- Windows 下启动Apache服务(转)
Win下apache出现问题:“No services installed”安装完apache之后(不是按照默认路径安装的,我的是 D:\ )右下方那个小羽毛图标是没有启动的,左键不好使,而且提示“N ...
- Android(java)学习笔记195:三重for循环的优化(Java面试题)
1.首先我们看一段代码: for(int i=0;i<1000;i++){ for(int j=0;j<100;j++){ for(int k=0;k<10;k++){ testFu ...
- jsp获取服务端的访问信息
获取服务端访问信息 public static String getUrl(HttpServletRequest request){ String url = ""; if(req ...
- (转)Spring读书笔记-----使用Spring容器(二)
一.使用ApplicationContext 前面介绍了,我们一般不会使用BeanFactory实例作为Spring容器,而是使用ApplicationContext实例作为容器,它增强了BeanFa ...
- ASP.NET MVC学习系列 WebAPI初探
转自http://www.cnblogs.com/babycool/p/3922738.html 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax( ...
- Activity以singleTask模式启动,intent传值的解决办法
转载请注明出处,谢谢http://blog.csdn.net/harryweasley/article/details/46557827 因为项目中,有一个消息推送的功能,每次推送一个消息,就会开启F ...