Linux與Windows編譯器的區別

移植工做開始後的第一步就是在目標平臺Linux上進行編譯,並連接源碼。由於需要移植的軟件一般並未在Linux平臺上編譯過,編譯的過程可能會遇到很是大的困難。普通狀況下,由類型聲明引發的編譯錯誤是比較easy修復的。比方Microsoft C/C++的頭文件使用__declspec( dllimport/dllexport )來輸入和輸出DLL函數,在Linux上,把函數聲明成extern 「C」,或者再結合使用DEF文件,使用對應的連接命令就可以解決這些問題。但困難的地方在於編譯器之間存在差別的部分,同一時候這也是可能引發很是多執行時問題的重要因素,讀者有必要在開始移植以前就充分了解。在此講述一些easy被忽略並且後果比較嚴重的方面。

  以Visual C++ 2003和GCC 4.1.0爲例。前者是Windows平臺的主流編譯器,兼容性良好,但是對C++標準的遵循並不嚴格。這意味着即便開發人員寫出不太符合標準的程序,編譯器也可能能容忍。相反的是,GCC對標準的遵循相對嚴格得多,這樣很是easy形成在Windows執行良好的程序,在Linux上卻引發意想不到的編譯甚至執行時錯誤。網絡

(1)基本類型大小和結構對齊

  首先是 C/C++語言基本類型的大小,以及對應的結構對齊問題。典型的樣例是longkeyword。在Visual C++ 2003下,sizeof(long double)是8,其大小和double一致。但是在GCC 4.1.0上,sizeof(long double)等於12,其大小比double多4。還有一個和大小相關的問題是對齊問題。不一樣編譯器的默認對齊大小是不同的。普通狀況下程序邏輯都跟對齊無關,但是涉及從磁盤或者網絡文件裏讀取結構時(如解析資源),精確的對齊就是必需的。考察如下的程序段:

#include 
struct A

{
char a;
double b;
};

int main()
{
printf("%d %d %d\n", sizeof(long double), 
sizeof(long long), sizeof(A) );
return 0;
}

  上面這段程序在 Visual C++ 2003編譯器默認設置下,輸出結果爲8 8 16;在GCC 4.1.0編譯器默認設置下,其輸出爲12 8 12。從sizeof(A)的大小可以看出,Visual C++ 2003是按8字節對齊的,而gcc是4字節對齊的。這時需要使用#pragma pack預編譯指令來改動頭文件裏的結構聲明,或者在執行時調整內存中結構成員的位置。不管採用何種方法,對齊都是需要當心處理的事情。

  一個引發最大麻煩的基本類型是wchar_t。在Visual C/C++ 2003編譯器中,wchar_t的大小是2字節,並且可以和unsigned short類型互相賦值。與此關聯的一系列Unicode相關函數,比方wcslen,wcscmp等,都接受UTF16格式的Unicode串。在 GCC中,其大小是32位。與此相關的wcslen,wcscmp函數都接受UTF32格式的Unicode串。爲此,必須在Linux上開發一套 UTF16接口的wcs系列函數,以保證UTF16的字符串被正確處理。與此同一時候,使用宏定義來替換wchar_tkeyword爲unsigned short,以保證函數聲明的兼容。函數

(2)new操做符的出錯處理

  還有一個問題是new操做符的出錯處理。由於編譯器的設置不一樣,new操做符可能具備不一樣的行爲。考察例如如下的代碼段:

#include 
class A
{
public:
void *operator new( size_t size )
{
return NULL;
}
A()
{
printf("Constructor called\n");
a = 0;
}
private:
int a;
};

int main()
{
A *p = new A();
printf("%x\n", p );
return 0;
}

  在Visual C++ 2003中,上面的程序輸出0。而GCC 4.1.0編譯器的輸出結果爲:

   Constructor called
   Segmentation fault

  也就是說,Visual C++ 2003的編譯器會檢查new的返回值,假設返回爲空,構造函數就再也不執行。但是gcc必須加上–fcheck-new編譯參數才具備這一行爲:g++ –fcheck-new test.cpp。這樣在Linux上上述程序也會輸出0。code

(3)結構化異常和C++異常

  還有一個更隱蔽的差別存在於異常處理。Visual C++並不遵循異常處理的C++規範。考察例如如下的程序段:

#include 
int main()
{
int* p = NULL;
try
{
*p = 0;
}
catch (...)
{
printf("caught the exception\n");
return 1;
}
return 0;
}

  讀者可以本身用 Visual C++ 2003和GCC分別檢驗這段程序。前者生成的程序在Windows上正常執行,輸出caught the exception,而後正常退出。而GCC生成的程序僅僅是輸出Segmentation fault。因此在Windows上,catch語句抓住了一個異常。依照C++的標準,惟獨使用throw語句,才幹產生異常。但是在上面的程序段中, 僅僅是一個簡單的賦值語句。緣由在於,Visual C++ 2003將C++的異常處理映射成了Windows的結構化異常處理。在上面的語句中,*p = 0將引發一個Windows的異常,Visual C++將它處理成一個C++異常,並進入catch塊。在Linux上,由於沒有C++異常發生,程序直接崩潰。接口

相關文章
相關標籤/搜索