GNU/Linux >> Tutoriales Linux >  >> Linux

¿Hay STDCALL en Linux?

La solución más simple es simplemente definir __stdcall a nada condicionalmente en Linux.


stdcall NO es solo una convención de llamadas; además de ser una convención de llamadas, permite un isomorfismo entre objetos C y C++. He aquí 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 se puedan usar desde C en plataformas que usan esta convención porque para enviar "Esto" a un método, debe establecer el registro ecx en la dirección de "Esto" en lugar de simplemente presionarlo, y de la misma manera si desea implementar una clase en C que C ++ pueda reconocer, el método deberá obtener este puntero del registro ecx, que no es accesible para C sin ensamblaje en línea o equivalente.

stdcall tiene esta agradable propiedad de que las clases que usan stdcall pueden usarse fácilmente simultáneamente desde C o C++ sin hacerles nada.

Entonces solo puedes #define __stdcall siempre y cuando no se ocupe de __thiscall; aunque puede haber algunas otras distinciones sutiles.


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 portar una aplicación de Windows de este tipo a Linux, necesita mucho más que simplemente definir __stdcall en nada:

#ifndef WIN32 // or something like that...
#define __stdcall
#endif

También necesitaría llamar a las funciones de la API específicas de Linux en lugar de las de la 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 ser entre moderadamente difícil y desalentador.

¿Qué funciones específicas marca la aplicación como __stdcall?

De hecho, el puerto de Windows de GCC debe tener __stdcall, porque se supone que puede generar código conforme a la plataforma Win32. Pero dado que en Linux solo existe una convención de llamada estándar y coincide con la salida del compilador predeterminada, esta declaración no es necesaria.

La razón por la que su aplicación no se compila en Linux se debe casi con seguridad al hecho de que hace referencia a las funciones de la API de 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 portar su aplicación a Linux sería usar 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 ejecutan en Linux.

Por supuesto, si realmente desea que se ejecute de forma nativa en Linux, la única forma de hacerlo es portarlo.


Linux
  1. Linux – ¿Sincronización de archivos en tiempo real?

  2. ¿La distribución de Linux se ejecuta completamente en Wayland (sin X11)?

  3. Comando IP de Linux

  4. Comando cd de linux

  5. Listar todos los montajes en Linux

Comando W en Linux

Al mando en Linux

Los 5 mejores temas de Linux Conky

¿Existe un cliente de OneDrive para Linux?

Linux frente a Unix

¿Existe alguna alternativa para JTS TestBuilder en Linux?