#navi_header|C言語系| "PASCAL"はヘッダーファイルで定義された呼び出し規約で、"__pascal"呼び出し規約のこと ''ではない。'' 実際にどの呼び出し規約("__stdcall", "__cdecl", "__pascal", ...)になるかは、OS/コンパイラによって異なってくるので、使用する場合は注意が必要。 ''ただし、2010年現在の Win32 APIプラットフォームにおいては基本的に PASCAL == "__stdcall" と考えて良い。'' VC++2008, Borland C++ Compiler, OpenWatcom(32bit), MinGW-gcc 共に、PASCALは"__stdcall"にdefineされている。 #more|| ---- #outline|| ---- * サンプルコード(big_pascal.c) VC++2008/Borland C++ Compiler/MinGW-gccで "PASCAL" を使うには、Windows用のヘッダーファイルをincludeする必要がある。今回は "windows.h" をincludeした。 windows.hをincludeしない場合、VC++2008/Borland C++ Compilerの両方で関数宣言の構文エラーとなりコンパイルに失敗する。 #code|c|> #include #include int PASCAL foo(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); return 0; } ||< * VC++2008 Express Edtion (obsoleted) プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__stdcall" にdefineされている事が分かる。 MSDN上では "obsoleted" となっており、"WINAPI"の方を使うよう推奨されている。 - Obsolete Calling Conventions (C++) -- http://msdn.microsoft.com/ja-jp/library/wda6h6df%28VS.80%29.aspx コンパイル&リンク&実行 #pre||> > cl /FAs /TC /Od /nologo /c big_pascal.c > link /SUBSYSTEM:CONSOLE /NOLOGO /OUT:big_pascal.exe big_pascal.obj > big_pascal.exe foo() = 150 ||< プリプロセス結果を生成: > cl /P /TC /Od /nologo /c big_pascal.c プリプロセス結果: #code|c|> #line 3 "big_pascal.c" int __stdcall foo(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); return 0; } ||< ** アセンブラ出力(big_pascal.asm) #pre||> ; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01 TITLE C:\in_vitro\c\cc_vc\big_pascal.c .686P .XMM include listing.inc .model flat INCLUDELIB LIBCMT INCLUDELIB OLDNAMES _DATA SEGMENT $SG78588 DB 'foo() = %d', 0aH, 00H _DATA ENDS PUBLIC _foo@20 ; Function compile flags: /Odtp ; File c:\in_vitro\c\cc_vc\big_pascal.c _TEXT SEGMENT _a$ = 8 ; size = 4 _b$ = 12 ; size = 4 _c$ = 16 ; size = 4 _d$ = 20 ; size = 4 _e$ = 24 ; size = 4 _foo@20 PROC ; 5 : { return a + b + c + d + e; } push ebp mov ebp, esp mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] add eax, DWORD PTR _c$[ebp] add eax, DWORD PTR _d$[ebp] add eax, DWORD PTR _e$[ebp] pop ebp ret 20 ; 00000014H _foo@20 ENDP _TEXT ENDS PUBLIC _main EXTRN _printf:PROC ; Function compile flags: /Odtp _TEXT SEGMENT _argc$ = 8 ; size = 4 _argv$ = 12 ; size = 4 _main PROC ; 7 : int main(int argc, char *argv[]) { push ebp mov ebp, esp ; 8 : printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); push 50 ; 00000032H push 40 ; 00000028H push 30 ; 0000001eH push 20 ; 00000014H push 10 ; 0000000aH call _foo@20 push eax push OFFSET $SG78588 call _printf add esp, 8 ; 9 : return 0; xor eax, eax ; 10 : } pop ebp ret 0 _main ENDP _TEXT ENDS END ||< * Borland C++ Compiler プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__stdcall" にdefineされている事が分かる。 アセンブラコードを生成 > bcc32 -S big_pascal.c コンパイル&実行 #pre||> > bcc32 big_pascal.c > big_pascal.exe foo() = 150 ||< プリプロセス結果を生成: > cpp32 big_pascal.c プリプロセス結果: #code|c|> /* big_pascal.c 3: */ /* big_pascal.c 4: */int __stdcall foo(int a, int b, int c, int d, int e) /* big_pascal.c 5: */{ return a + b + c + d + e; } /* big_pascal.c 6: */ /* big_pascal.c 7: */int main(int argc, char *argv[]) { /* big_pascal.c 8: */printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); /* big_pascal.c 9: */return 0; /* big_pascal.c 10: */} ||< ** アセンブラ出力(big_pascal.asm) #pre||> .386p ifdef ??version if ??version GT 500H .mmx endif endif model flat ifndef ??version ?debug macro endm endif ?debug S "big_pascal.c" ?debug T "big_pascal.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' foo proc near ?live1@0: ; ; int PASCAL foo(int a, int b, int c, int d, int e) ; push ebp mov ebp,esp ; ; { return a + b + c + d + e; } ; @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] add eax,dword ptr [ebp+24] @3: @2: pop ebp ret 20 foo endp _main proc near ?live1@48: ; ; int main(int argc, char *argv[]) { ; push ebp mov ebp,esp ; ; printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); ; @4: push 50 push 40 push 30 push 20 push 10 call foo push eax push offset s@ call _printf add esp,8 ; ; return 0; ; xor eax,eax ; ; } ; @6: @5: pop ebp ret _main endp _TEXT ends _DATA segment dword public use32 'DATA' s@ label byte ; s@+0: db "foo() = %d",10,0 align 4 _DATA ends _TEXT segment dword public use32 'CODE' _TEXT ends public foo public _main extrn __setargv__:near extrn _printf:near ?debug C 9F757569642E6C6962 ?debug C 9F757569642E6C6962 ?debug D "C:\in_vitro\apps\borland\bcc55\include\imm.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\mcx.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winsvc.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\commdlg.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\oleauto.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\propidl.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\oaidl.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\msxml.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\servprov.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\oleidl.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\urlmon.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\cguid.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\objidl.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\unknwn.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\search.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\stdlib.h" 10521 10272 ?debug D "C:\in_vitro\apps\borland\bcc55\include\objbase.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\ole2.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\prsht.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winspool.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winsmcrd.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winioctl.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnsip.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcndr.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\wtypes.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winscard.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winefs.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\wincrypt.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\qos.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winsock2.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winperf.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\shellapi.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcasync.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnterr.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnsi.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcdcep.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcdce.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\rpc.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\nb30.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\mmsystem.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\lzexpand.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\dlgs.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\ddeml.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\dde.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\cderr.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winnetwk.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winreg.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winver.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\wincon.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winnls.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\tvout.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winuser.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack1.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\wingdi.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winerror.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winbase.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack8.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack2.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\poppack.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack4.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\mem.h" 10521 10272 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_loc.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\locale.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_str.h" 10521 10272 ?debug D "C:\in_vitro\apps\borland\bcc55\include\string.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\guiddef.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\basetsd.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\mbctype.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\ctype.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\winnt.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\windef.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\stdarg.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\excpt.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\windows.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_nfile.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_null.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_defs.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\_stddef.h" 10339 10240 ?debug D "C:\in_vitro\apps\borland\bcc55\include\stdio.h" 10339 10240 ?debug D "big_pascal.c" 15473 34993 end ||< * OpenWatcom Compiler(16bit) プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__pascal" にdefineされている事が分かる。 コンパイル&リンク&実行 > set INCLUDE=%WATCOM%\h;%WATCOM%\h\win > wcl big_pascal.c アセンブラ生成: > wdis -a -l=big_pascal.asm big_pascal.obj プリプロセス結果を生成: > wcl -pcl -fo big_pascal.i big_pascal.c プリプロセス結果: #code|c|> #line 2 "big_pascal.c" int __pascal foo(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); return 0; } ||< ** アセンブラ出力(big_pascal.asm) #pre||> .387 PUBLIC FOO PUBLIC main_ EXTRN __STK:BYTE EXTRN printf_:BYTE EXTRN __argc:BYTE EXTRN _small_code_:BYTE EXTRN _cstart_:BYTE DGROUP GROUP CONST,CONST2,_DATA _TEXT SEGMENT BYTE PUBLIC USE16 'CODE' ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP FOO: mov ax,4 call near ptr __STK push bp mov bp,sp mov ax,word ptr 0cH[bp] add ax,word ptr 0aH[bp] add ax,word ptr 8[bp] add ax,word ptr 6[bp] add ax,word ptr 4[bp] pop bp ret 0aH main_: push ax mov ax,10H call near ptr __STK pop ax push bx push cx mov ax,0aH push ax mov ax,14H push ax mov ax,1eH push ax mov ax,28H push ax mov ax,32H push ax call near ptr FOO push ax mov ax,offset DGROUP:L$1 push ax call near ptr printf_ add sp,4 xor ax,ax pop cx pop bx ret _TEXT ENDS CONST SEGMENT WORD PUBLIC USE16 'DATA' L$1: DB 66H, 6fH, 6fH, 28H, 29H, 20H, 3dH, 20H DB 25H, 64H, 0aH, 0 CONST ENDS CONST2 SEGMENT WORD PUBLIC USE16 'DATA' CONST2 ENDS _DATA SEGMENT WORD PUBLIC USE16 'DATA' _DATA ENDS END ||< * OpenWatcom Compiler(32bit) プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__stdcall" にdefineされている事が分かる。 コンパイル&リンク&実行 > set INCLUDE=%WATCOM%\h;%WATCOM%\h\nt > wcl386 big_pascal.c アセンブラ生成: > wdis -a -l=big_pascal.asm big_pascal.obj プリプロセス結果を生成: > wcl386 -pcl -fo big_pascal.i big_pascal.c プリプロセス結果: #code|c|> #line 2 "big_pascal.c" int __stdcall foo(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); return 0; } ||< ** アセンブラ出力(big_pascal.asm) #pre||> .387 .386p .model flat PUBLIC `_foo@20` PUBLIC main_ EXTRN __CHK:BYTE EXTRN printf_:BYTE EXTRN __argc:BYTE EXTRN _cstart_:BYTE DGROUP GROUP CONST,CONST2,_DATA _TEXT SEGMENT BYTE PUBLIC USE32 'CODE' ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP `_foo@20`: push 4 call near ptr FLAT:__CHK mov eax,dword ptr 4[esp] add eax,dword ptr 8[esp] add eax,dword ptr 0cH[esp] add eax,dword ptr 10H[esp] add eax,dword ptr 14H[esp] ret 14H main_: push 1cH call near ptr FLAT:__CHK push ecx push 32H push 28H push 1eH push 14H push 0aH call near ptr FLAT:`_foo@20` push eax push offset FLAT:L$1 call near ptr FLAT:printf_ add esp,8 xor eax,eax pop ecx ret _TEXT ENDS CONST SEGMENT DWORD PUBLIC USE32 'DATA' L$1: DB 66H, 6fH, 6fH, 28H, 29H, 20H, 3dH, 20H DB 25H, 64H, 0aH, 0 CONST ENDS CONST2 SEGMENT DWORD PUBLIC USE32 'DATA' CONST2 ENDS _DATA SEGMENT DWORD PUBLIC USE32 'DATA' _DATA ENDS END ||< * GCC-3.4.5, MinGW-5.1.6, MSYS 1.0 プリプロセス結果およびアセンブラ出力から、"PASCAL" は "__attribute__()"版stdcall にdefineされている事が分かる。 コンパイル&リンク&実行 #pre||> $ gcc -O0 -Wall --save-temps -o big_pascal big_pascal.c $ big_pascal.exe foo() = 150 ||< プリプロセス結果: #code|c|> # 3 "big_pascal.c" 2 int __attribute__((__stdcall__)) foo(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo() = %d\n", foo(10, 20, 30, 40, 50)); return 0; } ||< ** アセンブラ出力(big_pascal.asm) #pre||> .file "big_pascal.c" .text .globl _foo@20 .def _foo@20; .scl 2; .type 32; .endef _foo@20: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax addl 20(%ebp), %eax addl 24(%ebp), %eax popl %ebp ret $20 .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "foo() = %d\12\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $24, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -4(%ebp) movl -4(%ebp), %eax call __alloca call ___main movl $50, 16(%esp) movl $40, 12(%esp) movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call _foo@20 subl $20, %esp movl %eax, 4(%esp) movl $LC0, (%esp) call _printf movl $0, %eax leave ret .def _printf; .scl 2; .type 32; .endef ||< #navi_footer|C言語系|