2011-11-10 72 views
5

我想使用WxWidgets,SDL等使用的相同的#ifdef方法。唯一的問題是我不知道如何使用它。如何使用預處理器來創建跨平臺庫?

說我想創建一個繪製矩形的類。我希望它在Win32平臺上使用時,在X11平臺(即Linux版)和GDI開羅:

class graphics 
{ 
void drawRect(int x, int y, int w, int h) 
{ 
/*if on win32*/ 
HDC myHdc = ::BeginPaint(myHwnd,&mypstr); 
::Rectangle(myHdc,x,y,w,h); 
::EndPaint(myHwnd,&mypstr); 

/*if on x11*/ 
cairo_surface_t* s = cairo_xlib_surface_create(/* args */); 
cairo_t* c = cairo_create(s); 
cairo_rectangle(c,x,y,w,h); 
// etc. etc. 
} 
}; 

我將如何使用#ifdef或別的東西來做到這一點?

+0

請不要WxWidgets和SDL提供您正在尋找的預處理器示例? –

+1

(+1)問題標題所代表的概念值得讚賞。沒有答案,閱讀其他開發人員的答案... – umlcat

回答

3

如果可以的話,喜歡把平臺的具體方法爲單獨的翻譯單位。這將允許更清晰的代碼更易讀,並且更易於開發和維護。恕我直言,構建過程應確定哪些平臺特定的模塊將納入。

例如:
rectangle.hpp:

struct Rectangle 
{ 
    void draw(int upper_left_corner_x, int upper_left_corner_y, 
      unsigned int length, unsigned int width); 
} 

現在特定於平臺的文件:
rectangle_wx_widgets.cpp:

#include "rectangle.hpp" 
void 
Rectangle :: 
draw(int upper_left_corner_x, int upper_left_corner_y, 
      unsigned int length, unsigned int width) 
{ 
// wxWidgets specific code here. 
} 

rectangle_qt.cpp:

#include "rectangle.hpp" 
void 
Rectangle :: 
draw(int upper_left_corner_x, int upper_left_corner_y, 
      unsigned int length, unsigned int width) 
{ 
// QT specific code here. 
} 

main.cpp中:

#include "rectangl.hpp" 
int main(void) 
{ 
    Rectangle r; 
    r.draw(50, 50, 10, 5); 
    return 0; 
} 

上面的代碼不包含任何條件預處理指令。無論平臺如何,main函數都繪製一個矩形。該平臺的細節已從main中刪除,因爲它們並不重要。因此,在不更改任何編譯器開關或擔心定義了哪個預處理器標識符的情況下,可以看到main無條件地繪製了一個矩形。

要使用wxWidgets平臺進行繪製,構建過程將使用rectangle_wx_widgets.cpp。要使用QT進行繪製,將使用rectangle_qt.cpp文件,但不能同時使用這兩個文件。如此圖所示,爲了爲任一平臺生成代碼,不更改代碼。人們可以調整構建過程,以便命令build wxWidgets包含正確的翻譯單元。因此,將參數傳遞給構建過程將生成特定於平臺的可執行文件。

+0

我同意你的解決方案看起來更清潔。 (+1),但我感覺有一兩個問題,如果我想改變標題中的內容,該怎麼辦?例如 如果windows'typedef HDC painter' else'typedef cairo_t painter' – ApprenticeHacker

+0

@IntermediateHacker:特定於平臺的文件可以包含特定於平臺的頭文件。在您的回覆示例中,您將創建一個特定於框架的通用'paint'方法。 Windows API將有一個'paint',而開羅則有一個'paint'。儘可能傳播下去。目標是減少條件預處理器指令的數量。 –

+0

謝謝。您的解決方案完美運作 – ApprenticeHacker

0

它們非常直接。

你想是這樣的:

#ifndef WIN32 
// something for X11 
#else 
// something for Windows 
#endif 

這只是一個知道默認的條件語句(如WIN3​​2在這種情況下)的問題。有操作系統,編譯器和很多可移植性的條件。

對於這種情況,請查看windows.h頭文件。它可能包含更多信息給你。

+0

你可能想'ifdef',以便你可以支持兩個以上。 –

0

有預定義的平臺變量,如WIN3​​2,您可以使用:

#ifdef WIN32 
.... 
#else 
.... 
#endif 
2

跨平臺並不意味着只有UNIX和Windows。此外,預定義的cpp指令可能依賴於編譯器。 提升平臺選擇源代碼是一個很好的開始,看看如何以正確的方式完成這項工作。看到config/select_platform_config.hpp 你可能也想看看cmake其中設置一些platform dependent defines

+0

對於「unix vs windows」的暗示感到抱歉,這不是意圖。我只是想解釋這一點。 – ApprenticeHacker

+1

沒有雙關意圖,我只是讓我的觀點 – user237419

+0

然後沒有問題。 (+1):) – ApprenticeHacker

0

有一個訣竅是,我沒有看到其他人提(編輯:sysfault提到它)。這裏有兩個不同的概念。預處理器命令將根據您的目標和您的編譯器而有所不同。也就是說,告訴你正在使用(GCC VS MSVC),該編譯器

#ifdef _MSC_VER 
    /*MSVC*/ 
#endif 
#ifdef __GNUC__ 
    /*GCC*/ 
#endif 

MSVC將只爲Windows編譯目標(據我們今天關注),以及GCC目標的一切。對於GCC,告訴 OS它的定位:

#ifdef __MINGW32__ 
    /* Windows */ 
#endif 
#ifdef BSD 
    /* BSD */ 
#endif 
#ifdef __linux__ 
    /* linux */ 
#endif 
#ifdef __APPLE__ 
    /* OSX */ 
#endif 

此外,有時你需要知道具體的處理器的東西,但不是操作系統:

__CHAR_UNSIGNED__ 
    GCC defines this macro if and only if the data type char is unsigned on the target machine. 
__BYTE_ORDER__ 
__ORDER_LITTLE_ENDIAN__ 
__ORDER_BIG_ENDIAN__ 
__ORDER_PDP_ENDIAN__ 
    __BYTE_ORDER__ is defined to one of the values __ORDER_LITTLE_ENDIAN__, __ORDER_BIG_ENDIAN__, or __ORDER_PDP_ENDIAN__ to reflect the layout of multi-byte and multi-word quantities in memory. 
__LP64__ 
_LP64 
    These macros are defined, with value 1, if (and only if) the compilation is for a target where long int and pointer both use 64-bits and int uses 32-bit. 

和許多許多其他