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 編譯的。

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

相關文章
相關標籤/搜索