ホームに戻る
 呼び出し規約

C言語には関数を呼び出すための規約があります。
__cdecl と __stdcall と __fastcall の3つがあり、
具体的な違いは引数の引き渡し方です。
違いがあるのはスタックフレームを解除する位置と、
引数の引渡しにレジスタを使うか?の2点です。

extern "C" はC++においてC言語の名前を採用します。
C++はオーバーロードがあるため、
コンパイラは関数に独特の名前付けを行いますが、
extern "C" をつけることでC言語の名前を利用できます。
この場合はもちろんオーバーロードはできません。

__cdecl

関数名は _func となる。
引数はスタックに入れる。
呼び出し側でスタックを add esp 12 などとして元に戻す。
Cの

__stdcall

関数名は func となる。
引数はスタックに入れる。
戻す側でスタックを ret 12 などとして元に戻す。

__fastcall

関数名は @func となる。
引数をレジスタに入れ、足りない場合はスタックに入れる。
戻す側で ret 4 などとして元に戻す。
引数がレジスタのみで送れれば理論上は早い。

__thiscall

this ポインタを ecx に入れるようです。
クラスのメンバ関数呼び出しに使われます。
その他の扱いは __stdcall と同じです。


 サンプルコード

#include <stdio.h>

int __cdecl f_cdecl(int a, int b, int c, int d){
  return a+b+c+d;
}

int __stdcall f_stdcall(int a, int b, int c, int d){
  return a+b+c+d;
}

int __fastcall f_fastcall(int a, int b, int c, int d){
  return a+b+c+d;
}

int main(){
  int t;

  t = f_cdecl(1, 2, 3, 4);
  t += f_stdcall(1, 2, 3, 4);
  t += f_fastcall(1, 2, 3, 4);

  printf("%d\n", t);

  return 0;
}

 ↓サンプルコードをアセンブラに展開(bcc32 -S にて)

	.386p
	ifdef ??version
	if    ??version GT 500H
	.mmx
	endif
	endif
	model flat
	ifndef	??version
	?debug	macro
	endm
	endif
	?debug	S "sample.c"
	?debug	T "sample.c"
_TEXT	segment dword public use32 'CODE'
_TEXT	ends
_DATA	segment dword public use32 'DATA'
_DATA	ends
_BSS	segment dword public use32 'BSS'
_BSS	ends
DGROUP	group	_BSS,_DATA
_TEXT	segment dword public use32 'CODE'
_f_cdecl	proc	near
?live1@0:
   ;	
   ;	int __cdecl f_cdecl(int a, int b, int c, int d){
   ;	
	push      ebp
	mov       ebp,esp
   ;	
   ;	  return a+b+c+d;
   ;	
@1:
	mov       eax,dword ptr [ebp+8]
	add       eax,dword ptr [ebp+12]
	add       eax,dword ptr [ebp+16]
	add       eax,dword ptr [ebp+20]
   ;	
   ;	}
   ;	
@3:
@2:
	pop       ebp
	ret 
_f_cdecl	endp
f_stdcall	proc	near
?live1@48:
   ;	
   ;	int __stdcall f_stdcall(int a, int b, int c, int d){
   ;	
	push      ebp
	mov       ebp,esp
   ;	
   ;	  return a+b+c+d;
   ;	
@4:
	mov       eax,dword ptr [ebp+8]
	add       eax,dword ptr [ebp+12]
	add       eax,dword ptr [ebp+16]
	add       eax,dword ptr [ebp+20]
   ;	
   ;	}
   ;	
@6:
@5:
	pop       ebp
	ret       16
f_stdcall	endp
@f_fastcall	proc	near
?live1@96:
   ;	
   ;	int __fastcall f_fastcall(int a, int b, int c, int d){
   ;	
	push      ebp
	mov       ebp,esp
   ;	
   ;	  return a+b+c+d;
   ;	
?live1@112: ; EAX = a, EDX = b, ECX = c
@7:
	add       edx,eax
	add       ecx,edx
	add       ecx,dword ptr [ebp+8]
	mov       eax,ecx
   ;	
   ;	}
   ;	
?live1@128: ; 
@9:
@8:
	pop       ebp
	ret       4
@f_fastcall	endp
_main	proc	near
?live1@144:
   ;	
   ;	int main(){
   ;	
	push      ebp
	mov       ebp,esp
	push      ebx
   ;	
   ;	  int t;
   ;	
   ;	  t = f_cdecl(1, 2, 3, 4);
   ;	
@10:
	push      4
	push      3
	push      2
	push      1
	call      _f_cdecl
	add       esp,16
	mov       ebx,eax
   ;	
   ;	  t += f_stdcall(1, 2, 3, 4);
   ;	
?live1@176: ; EBX = t
	push      4
	push      3
	push      2
	push      1
	call      f_stdcall
	add       ebx,eax
   ;	
   ;	  t += f_fastcall(1, 2, 3, 4);
   ;	
	push      4
	mov       ecx,3
	mov       edx,2
	mov       eax,1
	call      @f_fastcall
	add       ebx,eax
   ;	
   ;	
   ;	  printf("%d\n", t);
   ;	
	push      ebx
	push      offset s@
	call      _printf
	add       esp,8
   ;	
   ;	
   ;	  return 0;
   ;	
?live1@224: ; 
	xor       eax,eax
   ;	
   ;	}
   ;	
@12:
@11:
	pop       ebx
	pop       ebp
	ret 
_main	endp
_TEXT	ends
_DATA	segment dword public use32 'DATA'
s@	label	byte
	;	s@+0:
	db	"%d",10,0
	align	4
_DATA	ends
_TEXT	segment dword public use32 'CODE'
_TEXT	ends
	public	_f_cdecl
	public	f_stdcall
	public	@f_fastcall
	public	_main
 extrn   _printf:near
	?debug	D "c:\Borland\Bcc55\include\_nfile.h" 10339 10240
	?debug	D "c:\Borland\Bcc55\include\_null.h" 10339 10240
	?debug	D "c:\Borland\Bcc55\include\_defs.h" 10339 10240
	?debug	D "c:\Borland\Bcc55\include\_stddef.h" 10339 10240
	?debug	D "c:\Borland\Bcc55\include\stdio.h" 10339 10240
	?debug	D "sample.c" 13676 24088
	end

inserted by FC2 system