GNU/Linux >> Linux の 問題 >  >> Linux

Linux に STDCALL はありますか?

最も簡単な解決策は、Linux で条件付きで __stdcall を何も定義しないことです。


stdcall は単なる呼び出し規約ではありません。呼び出し規約であることに加えて、C と C++ オブジェクト間の同型性を許可します。以下に例を示します:

#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; 「This」をメソッドに送信するには、単にプッシュするのではなく、「This」のアドレスに ecx register を設定する必要があるため、cdecl がこの規則を使用するプラットフォームで C から C++ クラスを使用できないようにするのと同じではありません。 C++ が認識できるクラスを C で実装する場合、メソッドは、インライン アセンブリまたは等価物なしでは C にアクセスできない ecx レジスタから This ポインターを取得する必要があります。

stdcall には、stdcall を使用するクラスを、何もせずに C または C++ から簡単に同時に使用できるという優れた特性があります。

#define __stdcall しかできません __thiscall; を扱わない限り。他にも微妙な違いがあるかもしれませんが.


MSDN の __stdcall の説明へのリンクは次のとおりです:http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx

WinAPI 関数を呼び出すためにのみ使用されます。このような Windows アプリケーションを Linux に移植するには、__stdcall を何も定義しないだけでは不十分です。

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

また、Win32 API 関数の代わりに Linux 固有の API 関数を呼び出す必要があります。 Win32 API の特定の部分とアプリケーションのサイズ (コードの量) に応じて、中程度の難しさと困難の間のどこかになる可能性があります。

アプリによって __stdcall としてマークされている特定の関数はどれですか?

実際、GCC の Windows ポートには __stdcall が必要です。これは、Win32 プラットフォームに適合するコードを生成できるはずだからです。しかし、Linux では標準呼び出し規則が 1 つしかなく、デフォルトのコンパイラ出力と一致するため、このステートメントは必要ありません。

アプリケーションが Linux でコンパイルされない理由は、ほとんどの場合、Linux で定義されていない Win32 API 関数を参照しているという事実によるものです。適切な Linux の対応物を見つける必要があります。 Win32 API と Linux GLibc API は大きく異なり、簡単に置き換えることはできません。

おそらく、アプリを Linux に移植する最も簡単な方法は、Wine を使用することです。つまり、Linux の Wine でスムーズに動作するように Windows コードを変更します。これは、最新のコンピューター ゲームなどの最も複雑なアプリケーションでさえ、Linux で実行するために作成された方法です。

もちろん、Linux でネイティブに実行したい場合は、移植するしかありません。


Linux
  1. Linux –エントロピー品質を測定するためのツール?

  2. Linuxmvコマンド

  3. Linuxduコマンド

  1. Linuxipコマンド

  2. Linuxcdコマンド

  3. Linux の世界で .Net FileSystemWatcher に相当するものはありますか?

  1. Linux –リアルタイムのファイル同期?

  2. Linux 用の DirectX API がないのはなぜですか?

  3. Linux 上の JTS TestBuilder に代わるものはありますか?