整理日: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参数压栈是从左到右.

注意点

  1. 尽量不要在函数参数中运行象pop之类的参数
  2. 32bit和64bit同一源码时要注意

c/c++的函数参数压栈顺序的更多相关文章

  1. C语言函数参数压栈顺序为何是从右到左?(从左向右的话,碰到printf的会陷入死循环)

    上学期学习了汇编语言,并在操作系统实验中使用了汇编+C语言混合编程,中间也了解了一些C语言与汇编语言的对应关系. 由于汇编语言是底层的编程语言,各种函数参数都要直接控制栈进行存取,在混合编程中,要用汇 ...

  2. C/C++多参数函数参数的计算顺序与压栈顺序

    一.前言 今天在看Thinking in C++这本书时,书中的一个例子引起了我的注意,具体是使用了下面这句 单看这条语句的语义会发现仅仅是使用一个简单的string的substr函数将所得子串pus ...

  3. c语言中函数参数入栈的顺序是什么?为什么

    看到面试题C语言中函数参数的入栈顺序如何? 自己不知道,边上网找资料.下面是详细解释 #include <stdio.h> void foo(int x, int y, int z){   ...

  4. c++参数入栈顺序和参数计算顺序

    关于 本文涉及到代码,演示环境为:win10 + VS2017 ,ubuntu+clang clang版本: 参数入栈顺序 顺序 几种常见的函数参数入栈顺序,还有两种就不介绍了(__clrcall._ ...

  5. 在实验中观察指针——C++ 函数参数的压栈顺序

    前言 好久没写东西了,突发奇想,写写函数参数的压栈顺序 先看看这个问题 https://q.cnblogs.com/q/137133/ 然后看我简化的代码,猜输出结果是多少? #include< ...

  6. C语言函数入参压栈顺序为什么是从右向左?

    看到有人提问到,在处理printf/cout时,压栈顺序是什么样的?大家都知道是从右往左,也就是说从右往左的计算,但是,这里的计算不等于输出. a++和++a的压栈的区别:在计算时,遇到a++会记录此 ...

  7. C、C++语言中参数的压栈顺序

    要回答这个问题,就不得不谈一谈printf()函数,printf函数的原型是:printf(const char* format,-) 没错,它是一个不定参函数,那么我们在实际使用中是怎么样知道它的参 ...

  8. 测试当前C环境的栈帧增长方向以及传递参数时的压栈顺序

    前文链接:上次由于一个很常见的printf-bug(下文有提及)引发了我对栈的思考,并写下了一点总结.这次就尝试对不同的C环境进行实践,检测其传递参数的一些性质. 这是今天写的检查C环境的一段程序.能 ...

  9. C/C++---printf/cout 从右至左压栈顺序实例详解

    __cdecl压栈顺序实例 明白计算:计算是从右到左计算的 栈和寄存器变量:x++,是将计算结果存放到栈空间,最后是要出栈的:而++x和x是将计算结果直接存放到某个寄存器变量中(是同一个),所以计算完 ...

随机推荐

  1. 数据库:JDBC编程

    JDBC(Java Data Base Connectivity,java数据库连接)是一种用于运行SQL语句的Java API.能够为多种关系数据库提供统一訪问.它由一组用Java语言编写的类和接口 ...

  2. 【c++】虚函数描写叙述符override

    在C++11中为了帮助程序猿写继承结构复杂的类型,引入了虚函数描写叙述符override,假设派生类在虚函数声明时使用了override描写叙述符,那么该函数必须重载其基类中的同名函数,否则代码将无法 ...

  3. Android开发_Android数据的四种存储方式

    Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File.由于Android系统中,数据基本都是私有的的,都是存放 ...

  4. [TypeScript] Loading Compiled TypeScript Files in Browser with SystemJS

    TypeScript outputs JavaScript, but what are you supposed to do with it? This lesson shows how to tak ...

  5. Optimizing Linux network TCP/IP kernel parameters

    You can verify the Linux networking kernel parms from the root user with these commands::Many Oracle ...

  6. 阿里云SQL Server 2008 客户端导入数据库教程

    一.适用场景   源端数据库是SQL Server 2005 及以上.(SQL Server 2000未测试.) 数据文件总大小在10G以内. 可以在低峰期停应用.   二.导出步骤   1.软件准备 ...

  7. Java Stax操作XML简介

    使用stax操作xml 非常的简单,它的读取过程像是一个光标在移动.针对不同的节点做不同的处理. 先看一个基于光标的模型处理xml: public class StaxTest { @Test pub ...

  8. Android 开发实践 ViewGroup 实现左右滑出窗口(二)

    接上一篇 <Android 开发实践 ViewGroup 实现左右滑出窗口(一)http://www.cnblogs.com/inkheart0124/p/3532862.html> 源码 ...

  9. IDEA下安装/配置Jrebel

    IDEA下安装/配置Jrebel6.X 1. 为什么要使用Jrebel 在日常开发过程中, 一旦修改配置/在类中增加静态变量/增加方法/修改方法名等情况, tomcat不会自动加载, 需要重启tomc ...

  10. 消除热块(hot block)

    上篇日志提到了,那么高的负载,是存在数据块读竞争,下面介绍几个方法来消除块竟争 查找块竟争 SELECT p1 "file#", p2 "block#", p3 ...