2010-06-16 127 views
15

我正嘗試將Windows應用程序移植到Linux。此應用程序標記__stdcall屬性的一些功能。然而,我有一個朋友告訴我,stdcall僅用於windows,在linux中沒有意義(但是Windows GCC中存在)。 我試圖搜索谷歌關於這一點,並得到了一些結果表明,Linux中有stdacll。Linux中是否有STDCALL?

那麼...?

此外,對於海灣合作委員會,我看到了2個實現:__attribute__((__stdcall__))__attribute__((stdcall))(沒有下劃線附近stdcall)。 哪一個是首選的(如果適用於Linux)?

謝謝!

+5

stdcall只是一個調用*約定*,stdcall當然可以在Linux中存在,但它幾乎從來沒有使用過(可能除了Wine程序)。將您的程序轉換爲遵循本地約定更好。所以要回答你的問題,哪一個是首選的,就是不要使用stdcall。 stdcall在Linux程序中不合適。 – 2010-06-16 16:01:45

回答

8

最簡單的解決方案是在Linux上只將__stdcall定義爲無條件。

+0

它不會與GCC編譯。 – 2010-06-16 14:44:55

+1

這就是爲什麼我建議編寫一個擴展到「」的條件(僅限Linux)宏。 – dicroce 2010-06-16 22:34:15

8

這裏有一個鏈接到__stdcall MSDN上的描述: http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx

這只是用來調用WinAPI的功能。港口這樣的Windows應用程序到Linux,你需要的不僅僅是定義__stdcall不了了之更多:

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

您還需要調用Linux特有的API函數,而不是Win32 API的人。根據Win32 API的特定部分和應用程序的大小(代碼量),它可以處於適度困難和艱鉅的任何地方。

哪些特定功能被應用程序標記爲__stdcall?

事實上,GCC的Windows端口必須具有__stdcall,因爲它應該能夠生成符合Win32平臺的代碼。但是由於在Linux下只有一個標準調用約定,並且它與默認的編譯器輸出一致,所以不需要此語句。

你的應用程序在Linux下編譯的原因幾乎可以肯定是由於它引用了在Linux下沒有定義的Win32 API函數 - 你需要找到合適的Linux對應程序。 Win32 API和Linux GLibc API-s非常不同,不能輕易替換。

將應用程序移植到Linux的最簡單方法可能是使用Wine,即以這種方式修改Windows代碼,使其在Linux下的Wine下順利運行。即使是最複雜的應用程序,如現代計算機遊戲,也可以在Linux下運行。

當然,如果你真的希望它在Linux下本地運行,那麼移植是唯一的方法。

0

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;它不同於cdecl使得C++類在使用此約定的平臺上不能從C使用,因爲爲了向方法發送「This」,您必須將ecx寄存器設置爲「This」的地址,而不是僅僅推送它,並且同樣如果你想要在C中實現一個C++可以識別的類,那麼該方法需要從ecx寄存器中獲取這個指針,C無法訪問這個指針而沒有內聯裝配或等效。

stdcall具有這個不錯的屬性,使用stdcall的類可以輕鬆地同時從C或C++使用,而無需對它們執行任何操作。

所以你只能#define __stdcall只要你不處理__thiscall;儘管可能還有其他一些細微的區別。

相關問題