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是将计算结果直接存放到某个寄存器变量中(是同一个),所以计算完 ...
随机推荐
- 23讲 URL
这是看完23讲后的小笔记,关于URL规则.伪静态. 一.URL规则 2.此处的区分大小写,也只是对第一个字母区分,并非对整个模块名. 3.模块名复杂时,且区分大小写,此时在地址栏访问时要用" ...
- XRDP与VNC的关系
如果仅仅安装XRDP协议.是不能在windows上使用远程桌面连接到Ubuntu. 还须要安装VNCServer才行. 所以,XRDP启动之后.系统会自己主动启动一个VNC会话进程监听服务. 当我们通 ...
- 《细说 new与 malloc 的 10 点区别》
http://www.jobbole.com/members/melonstreet/
- System Operations on AWS - Lab 6W - Using Auto Scaling (Windows)
创建你的一个web server,然后将这个实例制成你的AMI,通过启动配置生成一个Auto Scaling组(包括scale-in/scale-out策略),配置一台Load Balancer指向你 ...
- Controller里写自己需要的Action,参数的名字必须和路由设置的参数名一致
Controller里写自己需要的Action,参数的名字必须和路由设置的参数名一致,如果参数不一致,传过去为null
- android应用一(调用WebServices)
搞了一个月的android,现学现卖,终于还是搞完了,停下来,整理思路,写写记录吧. 我们知道android访问远程数据库主要有两种协议,一种是SOAP,另外一种就是HTTP.而我们再看看WebSer ...
- homework做了些什么?
第一步:get_new_guid_uid_pairs_{$ymd} 参数是时间和100上的文件. 那么100上的文件是从哪里来的呢? 我们进入到100机器上,打开root权限下的cron,看到如下内容 ...
- php 半角与全角相关的正则
半角的全部确认,带小初音的确认法则 ^[ア-ン゙゚ァ-ョッヲー -]+$ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset// ...
- font awesome icon
http://fontawesome.io/icons/ http://www.bootstrapicons.com/
- Oracle 的merge into 用法
1.merge into的用途 Merge是一个非常有用的功能,与DB2中的merge into功能几乎一样,与Mysql里的insert into on duplicate key也很类似.MERG ...