GNU/Linux >> Linux Esercitazione >  >> Linux

C'è STDCALL in Linux?

La soluzione più semplice è semplicemente definire __stdcall a niente in modo condizionale su Linux.


stdcall NON è solo una convenzione di chiamata; oltre ad essere una convenzione di chiamata, consente un isomorfismo tra oggetti C e C++. Ecco un esempio:

#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; non è lo stesso che cdecl rende le classi C++ non utilizzabili da C su piattaforme che usano questa convenzione perché per inviare "This" a un metodo, devi impostare ecx register all'indirizzo di "This" invece di spingerlo semplicemente, e allo stesso modo se vuoi implementare una classe in C che C++ possa riconoscere, il metodo dovrà ottenere questo puntatore dal registro ecx che non è accessibile a C senza assembly inline o equivalente.

stdcall ha questa simpatica proprietà che le classi che usano stdcall possono essere facilmente utilizzabili contemporaneamente da C o C++ senza fare nulla per loro.

Quindi puoi solo #define __stdcall fintanto che non hai a che fare con __thiscall; anche se potrebbero esserci altre sottili distinzioni.


Ecco un collegamento alla descrizione di __stdcall su MSDN:http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx

Viene utilizzato solo per chiamare le funzioni WinAPI. Per eseguire il porting di un'applicazione Windows di questo tipo su Linux, è necessario molto di più della semplice definizione di __stdcall in nothing:

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

Dovresti anche chiamare le funzioni API specifiche di Linux invece di quelle API Win32. A seconda della parte specifica dell'API Win32 e delle dimensioni dell'applicazione (quantità di codice), può essere ovunque tra moderatamente difficile e scoraggiante.

Quali funzioni specifiche sono contrassegnate dall'app come __stdcall?

In effetti, il port Windows di GCC deve avere __stdcall, perché dovrebbe essere in grado di generare codice conforme per la piattaforma Win32. Ma poiché sotto Linux c'è solo una convenzione di chiamata standard e coincide con l'output predefinito del compilatore, questa istruzione non è necessaria.

Il motivo per cui la tua applicazione non viene compilata in Linux è quasi certamente dovuto al fatto che fa riferimento a funzioni API Win32 che non sono definite in Linux:devi trovare controparti Linux appropriate. L'API Win32 e l'API GLibc di Linux sono molto diverse e non possono essere sostituite facilmente.

Probabilmente il modo più semplice per portare la tua app su Linux sarebbe usare Wine, ovvero modificare il codice di Windows in modo tale che funzioni senza problemi sotto Wine in Linux. Questo è il modo in cui anche le applicazioni più complesse, come i moderni giochi per computer, sono state fatte girare sotto Linux.

Ovviamente, se vuoi davvero che funzioni in modo nativo sotto Linux, allora il porting è l'unica strada da percorrere.


Linux
  1. Linux:strumento per misurare la qualità dell'entropia?

  2. comando IP Linux

  3. comando cd di Linux

  4. Esiste un equivalente di .Net FileSystemWatcher nel mondo Linux?

  5. C'è un modo per ispezionare l'attuale rpath su Linux?

Comando W in Linux

Al comando in Linux

5 migliori temi Linux Conky

Esiste un client OneDrive per Linux?

Linux vs Unix

Come rimuovere un sistema Linux?