Die einfachste Lösung besteht darin, __stdcall unter Linux nur bedingt auf nichts zu definieren.
stdcall ist NICHT nur eine Aufrufkonvention; Es ist nicht nur eine Aufrufkonvention, sondern ermöglicht auch einen Isomorphismus zwischen C- und C++-Objekten. Hier ist ein Beispiel:
#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; es ist nicht dasselbe, dass cdecl C++-Klassen auf Plattformen, die diese Konvention verwenden, von C aus nicht verwendbar macht, denn um „This“ an eine Methode zu senden, müssen Sie ecx register auf die Adresse von „This“ setzen, anstatt es einfach zu pushen, und ebenso if Wenn Sie eine Klasse in C implementieren möchten, die C ++ erkennen kann, muss die Methode diesen Zeiger aus dem ecx-Register abrufen, auf das C ohne Inline-Assembly oder Äquivalent nicht zugreifen kann.
stdcall hat diese nette Eigenschaft, dass Klassen, die stdcall verwenden, problemlos gleichzeitig von C oder C++ aus verwendet werden können, ohne etwas mit ihnen zu tun.
Sie können also nur #define __stdcall
solange Sie sich nicht mit __thiscall befassen; obwohl es einige andere subtile Unterschiede geben könnte.
Hier ist ein Link zur __stdcall-Beschreibung auf MSDN:http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx
Es wird nur zum Aufrufen von WinAPI-Funktionen verwendet. Um eine solche Windows-Anwendung auf Linux zu portieren, brauchen Sie viel mehr, als nur __stdcall auf nichts zu setzen:
#ifndef WIN32 // or something like that...
#define __stdcall
#endif
Sie müssten auch die Linux-spezifischen API-Funktionen anstelle der Win32-API-Funktionen aufrufen. Abhängig vom jeweiligen Teil der Win32-API und der Größe der Anwendung (Menge an Code) kann dies zwischen mäßig schwierig und entmutigend sein.
Welche spezifischen Funktionen werden von der App als __stdcall gekennzeichnet?
In der Tat muss der Windows-Port von GCC __stdcall haben, da er in der Lage sein soll, konformen Code für die Win32-Plattform zu generieren. Da es aber unter Linux nur eine Standard-Aufrufkonvention gibt und diese mit der Standardausgabe des Compilers übereinstimmt, wird diese Anweisung nicht benötigt.
Der Grund, warum Ihre Anwendung nicht unter Linux kompiliert wird, liegt mit ziemlicher Sicherheit darin, dass sie auf Win32-API-Funktionen verweist, die nicht unter Linux definiert sind – Sie müssen geeignete Linux-Gegenstücke finden. Win32 API und Linux GLibc APIs sind sehr unterschiedlich und können nicht einfach ersetzt werden.
Die wahrscheinlich einfachste Möglichkeit, Ihre App auf Linux zu portieren, wäre die Verwendung von Wine, also den Windows-Code so zu modifizieren, dass er unter Wine unter Linux reibungslos läuft. Auf diese Weise wurden selbst die komplexesten Anwendungen, wie moderne Computerspiele, zum Laufen unter Linux gebracht.
Natürlich, wenn Sie wirklich wollen, dass es nativ unter Linux läuft, dann ist die Portierung der einzige Weg.