看到評論裡面有朋友抱怨以前文章裡面的例子都是 for Windows 的,沒有 for Linux 或者 for Mac 的。那麼今天就來說說跨平臺的問題吧!

所謂跨平臺,其實有兩種含義,一是跨硬體平臺,一是跨軟體平臺。對於硬體平臺,很多時候我們都會不自覺的忽略掉,因為硬體差異雖然很大,但是我們能夠接觸到的卻很少。目前 PC 系列基本都是相容的,並且編譯器可能會幫助我們完成這個問題,因此如果你的程式沒有用到組合語言,基本很難考慮到這種跨平臺的支援。但是,如果你的程式需要接觸到硬體,不管是因為功能的需要還是因為效能的需要,就不得不考慮這個問題。比如,Photoshop 的顏色處理直接使用匯編語言編寫,以達到最好效能,這就不得不考慮硬體相關的問題。通常我們說跨平臺,更多的只軟體的跨平臺,也就是跨作業系統。現在主流作業系統 Windows,Linux/Unix,基本算作是兩大陣營吧,它們之間的軟體都是不相容的,所以這種跨平臺是我們接觸比較多的。

說起跨平臺,就不得不提 Java。這是 Java 的賣點之一:“一次編寫,到處執行”。Java 之所以能夠實現跨平臺,是因為 Java 原始碼編譯成一種中間程式碼,執行 Java 程式,實際上是在 JVM 中。你編寫出的 Java 程式是跨平臺的,但是 JVM 不是跨平臺的,必須根據你的作業系統選擇 JVM。這是介面卡模式的典型應用 ?

選擇一個本身就是跨平臺的庫,你的工作量就會小很多,比如 Qt。Qt 已經幫我們封裝好很多平臺相關的程式碼。如果你開啟一個 Qt 的原始碼,就可能找到很多關於作業系統的判斷。簡單來說,我們使用 QMainWindow::show() 就可以顯示一個視窗。在 Windows 上,Qt 必須呼叫 Win32 API 完成;在 Linux 上,你就可能需要呼叫 GNOME 或者 KDE 的 API。但是,無論如何,這部分程式碼都不是我們關心的,因為 Qt 已經替我們完成了。所以,如果你的程式沒有與平臺相關的程式碼,那麼只需要在 Windows 上編譯成功,然後拿到 Linux 上重新編譯一下,通過一些簡單測試,或者還需要調整一下 UI 比例等等,就可以拿去發行了。

但是,如果有部分程式碼不得不依賴作業系統,比如我們呼叫列出目錄的命令,Windows 下是 dir,而 Linux 下是 ls,這就不得不根據平臺進行編譯了。這裡我們就拿這個例子嘗試一下。

mainwindow.h

  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.  
  4. #include <QMainWindow>  
  5.  
  6. class QProcess;  
  7.  
  8. class MainWindow : public QMainWindow  
  9. {  
  10.     Q_OBJECT  
  11.  
  12. public:  
  13.     MainWindow(QWidget *parent = 0);  
  14.     ~MainWindow();  
  15.  
  16. private slots:  
  17.     void openProcess();  
  18.     void readResult(int exitCode);  
  19.  
  20. private:  
  21.     QProcess *p;  
  22. };  
  23.  
  24. #endif // MAINWINDOW_H 

mainwindow.cpp

  1. #include <QProcess>  
  2. #include <QPushButton>  
  3. #include <QMessageBox>  
  4. #include <QTextCodec>  
  5.  
  6. #include "mainwindow.h"  
  7.  
  8. MainWindow::MainWindow(QWidget *parent)  
  9.     : QMainWindow(parent)  
  10. {  
  11.     p = new QProcess(this);  
  12.     QPushButton *bt = new QPushButton("display"this);  
  13.     connect(bt, SIGNAL(clicked()), this, SLOT(openProcess()));  
  14. }  
  15.  
  16. MainWindow::~MainWindow()  
  17. {  
  18.  
  19. }  
  20.  
  21. void MainWindow::openProcess()  
  22. {  
  23. #if defined(Q_OS_WIN32)  
  24.     p->start("cmd.exe", QStringList() << "/c" << "dir");  
  25. #elif defined(Q_OS_LINUX)  
  26.     p->start("ls", QStringList() << "/home/usr_name");  
  27. #endif  
  28.     connect(p, SIGNAL(finished(int)), this, SLOT(readResult(int)));  
  29. }  
  30.  
  31. void MainWindow::readResult(int exitCode)  
  32. {  
  33.     if(exitCode == 0) {  
  34. #if defined(Q_OS_WIN32)  
  35.         QTextCodec* gbkCodec = QTextCodec::codecForName("GBK");  
  36.         QString result = gbkCodec->toUnicode(p->readAll());  
  37. #elif defined(Q_OS_LINUX)  
  38.         QTextCodec* utfCodec = QTextCodec::codecForName("UTF-8");  
  39.         QString result = utfCodec->toUnicode(p->readAll());  
  40. #endif  
  41.         QMessageBox::information(this"dir", result);  
  42.     }  
  43. }  

例子和前面是一樣的,我們只是在 cpp 檔案中新增了一些程式碼。我們使用 #if 這些預處理指令通過判斷 Q_OS_WIN32 這樣的巨集是否存在,來生成相應的平臺相關的程式碼。這些巨集是在 Qt 中定義好的,我們只需根據它們是否存在進行判斷。這樣,我們的程式就可以在 Windows 和 Linux 下都可以編譯執行。

進行跨平臺程式設計,你不得不需要接觸到一些平臺相關的東西,比如文字元編碼等,都是需要好哈學習的。所以建議是儘可能使用 Qt 提供的標準函式進行程式設計,這樣就不必寫一大堆 if 判斷,程式碼也更加清晰。