c++ - ¿Hay STDCALL en Linux?
porting (3)
Aquí hay un enlace a la descripción de __stdcall en MSDN: http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx
Solo se usa para llamar a funciones de WinAPI. Para trasladar una aplicación de Windows a Linux, necesita mucho más que simplemente definir __stdcall a nada:
#ifndef WIN32 // or something like that...
#define __stdcall
#endif
También necesitarías llamar a las funciones de la API específicas de Linux en lugar de las API de Win32. Dependiendo de la parte particular de la API de Win32 y el tamaño de la aplicación (cantidad de código), puede estar en cualquier lugar entre moderadamente difícil y desalentador.
¿Qué funciones específicas están marcadas por la aplicación como __stdcall?
De hecho, el puerto de GCC de Windows debe tener __stdcall, porque se supone que puede generar código conforme para la plataforma Win32. Pero como en Linux solo hay una convención de llamada estándar y coincide con la salida predeterminada del compilador, esta declaración no es necesaria.
La razón por la que su aplicación no se está compilando en Linux es casi seguro que se debe al hecho de que hace referencia a las funciones de la API Win32 que no están definidas en Linux; debe encontrar las contrapartes de Linux adecuadas. Win32 API y Linux GLibc API-s son muy diferentes y no se pueden sustituir fácilmente.
Probablemente, la forma más fácil de migrar su aplicación a Linux sería utilizar Wine, es decir, modificar el código de Windows de tal manera que funcione sin problemas en Wine en Linux. Esta es la forma en que incluso las aplicaciones más complejas, como los juegos de computadora modernos, se han ejecutado bajo Linux.
Por supuesto, si realmente desea que se ejecute de forma nativa en Linux, entonces portar es la única manera de hacerlo.
Estoy tratando de portar una aplicación de Windows a Linux. Esta aplicación marca algunas funciones con el atributo __stdcall
. Sin embargo, un amigo me dijo que stdcall se usa solo en Windows y no tiene ningún significado en Linux (pero existe en Windows GCC). Traté de buscar en Google sobre eso, y obtuve algunos resultados que indican que hay STDACLL en Linux.
Asi que... ??
Además, para GCC vi 2 implementaciones para eso: __attribute__((__stdcall__))
y __attribute__((stdcall))
(sin los guiones bajos cerca de stdcall). ¿Cuál es el preferido (si se aplica a Linux)?
¡Gracias!
La solución más sencilla es simplemente definir __stdcall a nada condicionalmente en Linux.
stdcall NO es solo una convención de llamada; Además de ser una convención de llamada, permite un isomorfismo entre objetos C y C ++. Aquí hay un ejemplo:
#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; no es lo mismo que cdecl hace que las clases de C ++ no sean utilizables desde C en las plataformas que usan esta convención porque para enviar "Esto" a un método, debe configurar el registro ecx en la dirección de "Esto" en lugar de solo presionarlo, e igualmente desea implementar una clase en C que C ++ pueda reconocer, el método necesitará obtener este puntero del registro ecx que no es accesible a C sin ensamblaje en línea o equivalente.
stdcall tiene esta bonita propiedad de que las clases que usan stdcall se pueden utilizar fácilmente desde C o C ++ sin hacerles nada.
Por lo tanto, solo puede #define __stdcall
siempre y cuando no trate con __thiscall; aunque puede haber algunas otras distinciones sutiles.