GNU/Linux >> Tutoriels Linux >  >> Linux

Existe-t-il STDCALL sous Linux ?

La solution la plus simple consiste simplement à définir __stdcall sur rien de manière conditionnelle sous Linux.


stdcall n'est PAS simplement une convention d'appel; en plus d'être une convention d'appel, elle permet un isomorphisme entre les objets C et C++. Voici un exemple :

#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 ; ce n'est pas la même chose que cdecl rend les classes C++ inutilisables à partir de C sur les plates-formes utilisant cette convention car pour envoyer "This" à une méthode, vous devez définir le registre ecx sur l'adresse de "This" plutôt que de simplement le pousser, et de même si vous voulez implémenter une classe en C que C++ peut reconnaître, la méthode devra obtenir ce pointeur du registre ecx qui n'est pas accessible à C sans assemblage en ligne ou équivalent.

stdcall a cette belle propriété que les classes qui utilisent stdcall peuvent facilement être utilisables simultanément à partir de C ou C++ sans rien leur faire.

Vous ne pouvez donc que #define __stdcall tant que vous ne traitez pas avec __thiscall ; bien qu'il puisse y avoir d'autres distinctions subtiles.


Voici un lien vers la description de __stdcall sur MSDN :http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx

Il est uniquement utilisé pour appeler les fonctions WinAPI. Pour porter une telle application Windows vers Linux, vous avez besoin de bien plus que simplement définir __stdcall sur rien :

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

Vous devrez également appeler les fonctions API spécifiques à Linux au lieu de celles de l'API Win32. Selon la partie particulière de l'API Win32 et la taille de l'application (quantité de code), cela peut être n'importe où entre modérément difficile et intimidant.

Quelles fonctions spécifiques sont marquées par l'application comme __stdcall ?

En effet, le port Windows de GCC doit avoir __stdcall, car il est supposé pouvoir générer du code conforme pour la plate-forme Win32. Mais comme sous Linux il n'y a qu'une seule convention d'appel standard et qu'elle coïncide avec la sortie par défaut du compilateur, cette instruction n'est pas nécessaire.

La raison pour laquelle votre application ne compile pas sous Linux est presque certainement due au fait qu'elle fait référence à des fonctions API Win32 qui ne sont pas définies sous Linux - vous devez trouver des équivalents Linux appropriés. Les API Win32 et Linux GLibc sont très différentes et ne peuvent pas être remplacées facilement.

Le moyen le plus simple de porter votre application sur Linux serait probablement d'utiliser Wine, c'est-à-dire de modifier le code Windows de manière à ce qu'il fonctionne correctement sous Wine sous Linux. C'est ainsi que même les applications les plus complexes, comme les jeux informatiques modernes, ont été conçues pour fonctionner sous Linux.

Bien sûr, si vous voulez vraiment qu'il s'exécute nativement sous Linux, le portage est la seule solution.


Linux
  1. Linux – Outil pour mesurer la qualité de l'entropie ?

  2. Existe-t-il un équivalent au .Net FileSystemWatcher dans le monde Linux ?

  3. Existe-t-il un moyen d'inspecter le rpath actuel sous Linux ?

  4. Lister tous les montages sous Linux

  5. Existe-t-il une alternative à JTS TestBuilder sous Linux ?

Commande W sous Linux

À la commande sous Linux

5 meilleurs thèmes Linux Conky

Existe-t-il un client OneDrive pour Linux ?

Linux contre Unix

Existe-t-il une méthode pour obtenir un pourcentage sur un DD sous Linux?