C/C++中函数调用规则(约定)__cdecl __stdcall __thiscall __vectorcall __fastcall

相关文献c++

__stdcall
https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx算法

C语言函数可变参数详解 - ranpanf的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/ranpanf/article/details/4693130windows

关于c++变长参数列表总结 - zray4u的我的空间 -本身转载的另外一篇文章
http://my.oschina.net/ray1421/blog/699538app

注意平时咱们所说的参数传递顺序和参数入栈顺序是一回事。less

函数调用时,调用者首先把参数压入堆栈,而后调用子程序,在完成后,因为堆栈中先前压入的数再也不有用,调用者或者被调用者必须有一方把堆栈指针恢复到调用前的状态。参数是最右边的先入堆栈仍是最左边的先入堆栈、还有由调用者仍是被调用者来修正堆栈都必须有个约定,否则就会产生不正确的结果。ide

https://yq.aliyun.com/articles/34353函数

_cdecl  这个名字起的难道是 C default calling的意思性能

__cdecl is the default calling convention(默认的调用约定) for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions.(这里提供了一条很是重要的信息:只有由调用者来清理堆栈的函数才可以声明为变参函数) The __cdecl calling convention creates larger executables than __stdcall,(这种方式生成的可执行程序要比_stdcall方式生成的可执行文件要大) because it requires each function call to include stack cleanup code. The following list shows the implementation of this calling convention.下面的表格中主要包含:ui

参数传递顺序:从右向左   (注:注意区别参数传递顺序与参数计算顺序,在c++中并无规定参数计算顺序。) this

cout和printf的缓冲机制 / 蓝讯  http://www.lxway.com/66081202.htm

堆栈维护责任:调用函数将参数从堆栈中pop.

名称修饰约定:指的是根据何种算法来为每一个函数生成一个惟一的名字

case-translation convention:?????

image

On ARM and x64 processors, __cdecl is accepted but typically ignored by the compiler. By convention on ARM and x64, arguments are passed in registers when possible, and subsequent arguments are passed on the stack. In x64 code, use __cdecl to override the /Gv compiler option and use the default x64 calling convention.

For non-static class functions, if the function is defined out-of-line, the calling convention modifier does not have to be specified on the out-of-line definition. That is, for class non-static member methods, the calling convention specified during declaration is assumed at the point of definition.

对于非静态类成员函数,若是函数的定义不一致,调用方式修饰符并不必定要在不一致的定义中指定,即对于类中的非静态成员函数,在声明时指定的调用方式约定将在定义时呈现。

Given this class definition:

struct CMyClass { void __cdecl mymethod(); };

this:

void CMyClass::mymethod() { return; }   //即只要在声明中指定便可,而不要在定义再从新声明,防止形成不一致,而拔苗助长。
is equivalent to this:

void __cdecl CMyClass::mymethod() { return; }

Example

In the following example, the compiler is instructed to use C naming and calling conventions for the system function.

// Example of the __cdecl keyword on function
int __cdecl system(const char *);
// Example of the __cdecl keyword on function pointer
typedef BOOL (__cdecl *funcname_ptr)(void * arg1, const char * arg2, DWORD flags, ...);

===========================

The document is archived and information here might be outdated

__stdcall

Microsoft Specific

The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack(被调用者清理堆栈。note:这也是没办法的事,由于若是用户程序调用win32 API, 因为windows内部实现的不了解,没法完成相关的清理工做,即便微软提供了相关的实现说明,由用户来承担相关的清理工做也多是一项繁琐的工做,甚至可能形成系统的不稳定。), so the compiler makes vararg functions __cdecl. Functions that use this calling convention require a function prototype.

 

return-type __stdcall function-name[(argument-list)]

The following list shows the implementation of this calling convention.

image

The /Gz compiler option specifies __stdcall for all functions not explicitly declared with a different calling convention.

对于全部没有显式用其余调用约定声明的函数,Gz编译器默认指定为__stdcall.(note:前面不是说__cdecl是C和c++默认的调用方式吗?)

Functions declared using the __stdcall modifier return values the same way as functions declared using __cdecl.

On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; on ARM and x64 architectures, by convention, arguments are passed in registers when possible, and subsequent arguments are passed on the stack.

For non-static class functions, if the function is defined out-of-line, the calling convention modifier does not have to be specified on the out-of-line definition. That is, for class non-static member methods, the calling convention specified during declaration is assumed at the point of definition. Given this class definition,

上面这两段和下面这一段与前面介绍__cdecl中的内容大体相同。

C++

struct CMyClass { void __stdcall mymethod(); };

this

C++

void CMyClass::mymethod() { return; }

is equivalent to this

C++

void __stdcall CMyClass::mymethod() { return; }

Example

In the following example, use of __stdcall results in all WINAPI function types being handled as a standard call:

C  //操做系统函数通常者是用c语言编写。

// Example of the __stdcall keyword
#define WINAPI __stdcall
// Example of the __stdcall keyword on function pointer

//这里…是表示变参的意思吗???
typedef BOOL (__stdcall *funcname_ptr)\(void * arg1, const char * arg2, DWORD flags, ...);  

=================================

__fastcall

Microsoft Specific

The __fastcall calling convention specifies that arguments to functions are to be passed in registers, (note:用寄存器传参确实会比较快)when possible. This calling convention only applies to the x86 architecture. (note:对于x64不须要指定就是这样,上文有说起)The following list shows the implementation of this calling convention.

__fastcall的前两个参数会放入ecx,edx  (下面表格中第一行也有说明)

image

Future compiler versions may use different registers to store parameters.

Using the /Gr compiler option causes each function in the module to compile as __fastcall unless the function is declared by using a conflicting attribute, or the name of the function is main.

The __fastcall keyword is accepted and ignored by the compilers that target ARM and x64 architectures; on an x64 chip, by convention, the first four arguments are passed in registers when possible, and additional arguments are passed on the stack. On an ARM chip, up to four integer arguments and eight floating-point arguments may be passed in registers, and additional arguments are passed on the stack.(note:在arm中可以用寄存器传递的参数的个数也是受限的,额外的参数仍然在栈上传递)

C++

struct CMyClass {
   void __fastcall mymethod();
};

this:

C++

void CMyClass::mymethod() { return; }

is equivalent to this:

C++

void __fastcall CMyClass::mymethod() { return; }

Example

In the following example, the function DeleteAggrWrapper is passed arguments in registers:

C

// Example of the __fastcall keyword
#define FASTCALL    __fastcall

void FASTCALL DeleteAggrWrapper(void* pWrapper);
// Example of the __ fastcall keyword on function pointer
typedef BOOL (__fastcall *funcname_ptr)(void * arg1, const char * arg2, DWORD flags, ...);

-------------------------------
__thiscall  C++成员函数专用,不支持变参。

The __thiscall calling convention is used on member functions and is the default calling convention used by C++ member functions that do not use variable arguments. Under __thiscall, the callee cleans the stack, which is impossible for vararg functions. Arguments are pushed on the stack from right to left, with the this pointer being passed via register ECX(note:???????), and not on the stack, on the x86 architecture.

One reason to use __thiscall is in classes whose member functions use __clrcall by default. In that case, you can use __thiscall to make individual member functions callable from native code.(基本不会用到)

When compiling with /clr:pure, all functions and function pointers are __clrcall unless specified otherwise.

In releases before Visual C++ 2005, the thiscall calling convention could not be explicitly specified in a program, because thiscall was not a keyword.

vararg member functions use the __cdecl calling convention. All function arguments are pushed on the stack, with the this pointer placed on the stack last.(note:并非全部的成员函数只能指定为__thiscall函数调用方式,对于变参成员函数,调用方式使用的是__cdecl,并且也只能是这个。this指针是类的非静态成员函数的一个隐含的参数,它被放在函数堆栈中是全部参数中最后一个被放入堆栈的。)

Because this calling convention applies only to C++, there is no C name decoration scheme.

On ARM and x64 machines, __thiscall is accepted and ignored by the compiler.

For non-static class functions, if the function is defined out-of-line, the calling convention modifier does not have to be specified on the out-of-line definition. That is, for class non-static member methods, the calling convention specified during declaration is assumed at the point of definition.

Example

// thiscall_cc.cpp
// compile with: /c /clr:oldSyntax
struct CMyClass {
   void __thiscall mymethod();
   void __clrcall mymethod2();
};
-----------------------------

 

 

__vectorcall

Microsoft Specific

The __vectorcall calling convention specifies that arguments to functions are to be passed in registers, when possible. __vectorcall uses more registers for arguments than __fastcall or the default x64 calling convention use. The __vectorcall calling convention is only supported in native code on x86 and x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above. Use __vectorcall to speed functions that pass several floating-point or SIMD vector arguments and perform operations that take advantage of the arguments loaded in registers. The following list shows the features that are common to the x86 and x64 implementations of __vectorcall.

image

Using the /Gv compiler option(note:这个选项中后面的v表明了__vectorcall) causes each function in the module to compile as __vectorcall unless the function is a member function, is declared with a conflicting calling convention attribute(note:这里指的是用另外一种调用约定属性指定), uses a vararg variable argument list, or has the name main.(note:一些不能使用__vectorcall的状况,另外若是有变参列表,只能用__cdecl,另外对于main函数不能使用__fastcall、__thiscall、__vectorcall,可使用的只有__cdecl、__stdcall)。

You can pass three kinds of arguments by register in __vectorcall functions: integer type values, vector type values, and homogeneous vector aggregate (HVA) values.

An integer type satisfies two requirements: it fits in the native register size of the processor—for example, 4 bytes on an x86 machine or 8 bytes on an x64 machine—and it’s convertible to an integer of register length and back again without changing its bit representation. For example, any type that can be promoted to int on x86 (long long on x64)—for example, a char or short—or that can be cast to int (long long on x64) and back to its original type without change is an integer type. Integer types include pointer, reference, and struct or union types of 4 bytes (8 bytes on x64) or less. On x64 platforms, larger struct and union types are passed by reference to memory allocated by the caller; on x86 platforms, they are passed by value on the stack.

A vector type is either a floating-point type—for example, a float or double—or an SIMD vector type—for example, __m128 or __m256.

注:Single Instruction Multiple Data,单指令多数据流,可以复制多个操做数,并把它们打包在大型寄存器的一组指令集。

----------------------

__clrcall 

(我的理解只有用到托管代码和c++代码相互调用时才须要关注,并且只在windows下有效)

指定只能从托管代码调用的函数。对全部只能从托管代码调用的虚函数使用 __clrcall。 可是,此调用约定不能用于从本机代码调用的函数。

当经过指针从托管函数调用到虚拟托管函数或从托管函数调用到托管函数时,可以使用 __clrcall 来提升性能。

入口点是编译器生成的单独函数。 若是函数同时具备本机和托管入口点,则其中一个将是具备函数实现的实际函数。 其余函数将是调用到实际函数的单独函数(形式转换 (thunk))并容许公共语言运行时执行 PInvoke。 当将函数标记为 __clrcall 时,您能够指示函数实现必须是 MSIL,而且不生成本机入口点函数。

当采用本机函数的地址时,若是未指定 __clrcall,编译器将使用本机入口点。 __clrcall 指示函数为托管函数,而且不须要经历从托管到本机的转换。 在这种状况下,编译器将使用托管入口点。

当使用了 /clr(不是 /clr:pure/clr:safe )而未使用 __clrcall 时,采用函数的地址将始终返回本机入口点函数的地址。 当使用了 __clrcall 时,不会建立本机入口点函数,所以您将得到托管函数的地址,而不是入口点形式转换 (thunk) 函数的地址。 有关详细信息,请参阅双重 Thunk (C++)

/clr(公共语言运行时编译) 表示全部函数和函数指针都是 __clrcall,且编译器不容许将编译单位中的函数标记为 __clrcall 以外的任何内容。 当使用 /clr:pure 时,__clrcall 只能在函数指针和外部声明上指定。

能够直接从使用 /clr 编译的现有 C++ 代码调用 __clrcall 函数(只要该函数具备 MSIL 实现)。 例如,__clrcall 函数没法直接从具备内联 asm 的函数调用,且没法调用特定于 CPU 的内部函数,即便这些函数是使用 /clr 编译的。

-------------------

相关文章
相关标签/搜索