最も簡単な解決策は、Linux で条件付きで __stdcall を何も定義しないことです。
stdcall は単なる呼び出し規約ではありません。呼び出し規約であることに加えて、C と C++ オブジェクト間の同型性を許可します。以下に例を示します:
#define _CRT_SECURE_NO_WARNINGS // disable marking use of strcpy as error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class ICdeclGreeter {
public:
virtual ~ICdeclGreeter(){}
virtual void setGreeting(const char *greeting) = 0;
virtual void greet() = 0;
};
class IStdcallGreeter {
public:
virtual __stdcall ~IStdcallGreeter(){}
virtual void __stdcall setGreeting(const char *greeting) = 0;
virtual void __stdcall greet() = 0;
};
class CdeclGreeter : public ICdeclGreeter {
public:
char *greeting;
~CdeclGreeter() {
if (greeting != nullptr) {
free(greeting);
puts("[CdeclGreeter] destroyed");
}
}
void setGreeting(const char *greeting) {
this->greeting = (char *)malloc(strlen(greeting) + 1);
strcpy(this->greeting, greeting);
}
void greet() {
puts(greeting);
}
};
class StdcallGreeter : public IStdcallGreeter {
public:
char *greeting;
__stdcall ~StdcallGreeter() {
if (greeting != nullptr) {
free(greeting);
puts("[StdcallGreeter] destroyed");
}
}
void __stdcall setGreeting(const char *greeting) {
this->greeting = (char *)malloc(strlen(greeting) + 1);
strcpy(this->greeting, greeting);
}
void __stdcall greet() {
puts(greeting);
}
};
typedef struct pureC_StdcallGreeter pureC_StdcallGreeter;
typedef struct pureC_StdcallGreeterVtbl {
void (__stdcall *dtor)(pureC_StdcallGreeter *This);
void (__stdcall *setGreeting)(pureC_StdcallGreeter *This, const char *greeting);
void (__stdcall *greet)(pureC_StdcallGreeter *This);
} pureC_IStdcallGreeterVtbl;
struct pureC_StdcallGreeter {
pureC_IStdcallGreeterVtbl *lpVtbl;
char *greeting;
int length;
};
/* naive attempt at porting a c++ class to C;
on x86, thiscall passes This via ecx register rather than
first argument; this register cannot be accessed in C without
inline assembly or calling a reinterpretation of byte array
as a function. there is no "This" argument in any of below. */
typedef struct pureC_CdeclGreeter pureC_CdeclGreeter;
typedef struct pureC_CdeclGreeterVtbl {
void (*dtor)(pureC_CdeclGreeter *This);
void (*setGreeting)(pureC_CdeclGreeter *This, const char *greeting);
void (*greet)(pureC_CdeclGreeter *This);
} pureC_CdeclGreeterVtbl;
struct pureC_CdeclGreeter {
pureC_CdeclGreeterVtbl *lpVtbl;
char *greeting;
int length;
};
void test() {
ICdeclGreeter *g = new CdeclGreeter;
g->setGreeting("hi");
g->greet();
IStdcallGreeter *g2 = new StdcallGreeter;
g2->setGreeting("hi");
g2->greet();
// we can pass pointers to our object to pure C using this interface,
// and it can still use it without doing anything to it.
pureC_StdcallGreeter *g3 = (pureC_StdcallGreeter *)g2;
g3->lpVtbl->setGreeting(g3, "hello, world!");
g3->lpVtbl->greet(g3);
g3->lpVtbl->dtor(g3);
free(g2);
/*
// cdecl passes this via ecx in x86, and not as the first argument;
// this means that this argument cannot be accessed in C without
// inline assembly or equivelent. Trying to run code below will cause a runtime error.
pureC_CdeclGreeter *g4 = (pureC_CdeclGreeter *)g;
g4->lpVtbl->setGreeting(g4, "hello, world!");
g4->lpVtbl->greet(g4);
g4->lpVtbl->dtor(g4);
free(g);
*/
delete g;
}
int main(int argc, char **argv)
{
test();
system("pause");
return 0;
}
TLDR; 「This」をメソッドに送信するには、単にプッシュするのではなく、「This」のアドレスに ecx register を設定する必要があるため、cdecl がこの規則を使用するプラットフォームで C から C++ クラスを使用できないようにするのと同じではありません。 C++ が認識できるクラスを C で実装する場合、メソッドは、インライン アセンブリまたは等価物なしでは C にアクセスできない ecx レジスタから This ポインターを取得する必要があります。
stdcall には、stdcall を使用するクラスを、何もせずに C または C++ から簡単に同時に使用できるという優れた特性があります。
#define __stdcall
しかできません __thiscall; を扱わない限り。他にも微妙な違いがあるかもしれませんが.
MSDN の __stdcall の説明へのリンクは次のとおりです:http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx
WinAPI 関数を呼び出すためにのみ使用されます。このような Windows アプリケーションを Linux に移植するには、__stdcall を何も定義しないだけでは不十分です。
#ifndef WIN32 // or something like that...
#define __stdcall
#endif
また、Win32 API 関数の代わりに Linux 固有の API 関数を呼び出す必要があります。 Win32 API の特定の部分とアプリケーションのサイズ (コードの量) に応じて、中程度の難しさと困難の間のどこかになる可能性があります。
アプリによって __stdcall としてマークされている特定の関数はどれですか?
実際、GCC の Windows ポートには __stdcall が必要です。これは、Win32 プラットフォームに適合するコードを生成できるはずだからです。しかし、Linux では標準呼び出し規則が 1 つしかなく、デフォルトのコンパイラ出力と一致するため、このステートメントは必要ありません。
アプリケーションが Linux でコンパイルされない理由は、ほとんどの場合、Linux で定義されていない Win32 API 関数を参照しているという事実によるものです。適切な Linux の対応物を見つける必要があります。 Win32 API と Linux GLibc API は大きく異なり、簡単に置き換えることはできません。
おそらく、アプリを Linux に移植する最も簡単な方法は、Wine を使用することです。つまり、Linux の Wine でスムーズに動作するように Windows コードを変更します。これは、最新のコンピューター ゲームなどの最も複雑なアプリケーションでさえ、Linux で実行するために作成された方法です。
もちろん、Linux でネイティブに実行したい場合は、移植するしかありません。