免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
從 Windows 移植到 UNIX
Visual C++ 和 GNU g++ 內(nèi)部探密
2008-06-06 02:44
Visual C++ 和 GNU g++ 都為 cl 編譯器提供了一些選項。盡管您可以使用 cl 作為獨立的工具進(jìn)行編譯工作,但是,Visual C++ 提供了一種靈活的集成開發(fā)環(huán)境 (IDE) 以設(shè)置編譯器選項。使用 Visual Studio® 開發(fā)的軟件通常使用了一些編輯器特定的和平臺相關(guān)的特性,可以使用編譯器或者連接器來控制這些特性。當(dāng)您在不同的平臺(使用了不同的編譯器或者工具鏈)之 間移植源代碼的時候,了解編譯器的相關(guān)選項,這一點是非常重要的。這部分內(nèi)容深入分析了一些最有價值的編譯器選項。
可以考慮下面的代碼片段:
char *string1= "This is a character buffer";
char *string2= "This is a character buffer";
如果在 Visual C++ 中啟用了字符串池選項 [/GF],那么在執(zhí)行期間,將在程序的映像中僅保存該字符串的單個副本,且 string1 與 string2 相等。需要說明的是,g++ 的行為正好與它相反,在缺省情況下,string1 與 string2 相等。要在 g++ 中禁用字符串池,您必須將 -fwritable-strings 選項添加到 g++ 命令行。
C++ 標(biāo)準(zhǔn)定義了 wchar_t 寬字符類型。如果將 /Zc:wchar_t 選項傳遞給編譯器,那么 Visual C++ 會將 wchar_t 作為本地類型。否則,需要包含一些實現(xiàn)特定的 Header,如 windows.h 或者一些標(biāo)準(zhǔn)的 Header(如 wchar.h)。g++ 支持本地 wchar_t 類型,并且不需要包括特定的 Header。請注意,在不同的平臺之間,wchar_t 的大小是不相同的。您可以使用 -fshort-wchar g++ 選項將 wchar_t 的大小強(qiáng)制規(guī)定為兩個字節(jié)。
如果源代碼沒有使用 dynamic_cast 或者 typeid 操作符,那么就可以禁用運行時類型識別 (RTTI)。在缺省情況下,Visual Studio 2005 中打開了 RTTI(即 /GR 開關(guān)處于打開狀態(tài))??梢允褂?/GR- 開關(guān)在 Visual Studio 環(huán)境中禁用 RTTI。禁用 RTTI 可能有助于產(chǎn)生更小的可執(zhí)行文件。請注意,在包含 dynamic_cast 或者 typeid 的代碼中禁用 RTTI,可能會產(chǎn)生一些負(fù)面的影響,包括代碼崩潰??梢钥紤]清單 1 中的代碼片段。
#include <iostream>
struct A {
virtual void f()
{ std::cout << "A::f\n"; }
};
struct B : A {
virtual void f()
{ std::cout << "B::f\n"; }
};
struct C : B {
virtual void f()
{ std::cout << "C::f\n"; }
};
int main (int argc, char** argv )
{
A* pa = new C;
B* pb = dynamic_cast<B*> (pa);
if (pb)
pb->f();
return 0;
}
為在 Visual Studio IDE 之外獨立的 cl 編譯器中編譯這個代碼片段,需要顯式地打開 /GR 切換開關(guān)。與 cl 不同,g++ 編譯器不需要任何特殊的選項以打開 RTTI。然而,與 Visual Studio 中的 /GR- 選項一樣,g++ 提供了 -fno-rtti 選項,用以顯式地關(guān)閉 RTTI。在 g++ 中使用 -fno-rtti 選項編譯這個代碼片段,將報告編譯錯誤。然而,即使 cl 在編譯這個代碼時不使用 /GR 選項,但是生成的可執(zhí)行文件在運行時將會崩潰。
要在 cl 中啟用異常處理,可以使用 /GX 編譯器選項或者 /EHsc。如果不使用這兩個選項,try 和 catch 代碼仍然可以執(zhí)行,并且系統(tǒng)執(zhí)行到 throw 語句時才會調(diào)用局部對象的析構(gòu)函數(shù)。異常處理會帶來性能損失。因為編譯器將為每個 C++ 函數(shù)生成進(jìn)行堆展開的代碼,這種需求將導(dǎo)致更大的可執(zhí)行文件、更慢的運行代碼。對于特定的項目,有時無法接受這種性能損失,那么您需要關(guān)閉該特性。要禁用 異常處理,您需要從源代碼中刪除所有的 try 和 catch 塊,并使用 /GX- 選項編譯代碼。在缺省情況下,g++ 編譯器啟用了異常處理。將 -fno-exceptions 選項傳遞給 g++,會產(chǎn)生所需的效果。請注意,對包含 try、catch 和 throw 關(guān)鍵字的源代碼使用這個選項,可能會導(dǎo)致編譯錯誤。您仍然需要手工地從源代碼中刪除 try 和 catch 塊(如果有的話),然后將這個選項傳遞給 g++。可以考慮清單 2 中的代碼。
#include <iostream>
using namespace std;
class A { public: ~A () { cout << "Destroying A "; } };
void f1 () { A a; throw 2; }
int main (int argc, char** argv ) {
try { f1 (); } catch (...) { cout << "Caught!\n"; }
return 0;
}
下面是 cl 和 g++ 在使用以及不使用該部分中所介紹的相關(guān)選項時得到的輸出結(jié)果:
cl 使用 /GX 選項: Destroying A Caught! cl 不使用 /GX 選項: Caught! g++ 不使用 -fno-exceptions: Destroying A Caught! g++ 使用 -fno-exceptions:編譯時間錯誤
對于循環(huán)的一致性,可以考慮清單 3 中的代碼片段。
int main (int argc, char** argv )
{
for (int i=0; i<5; i++);
i = 7;
return 0;
}
根據(jù) ISO C++ 的指導(dǎo)原則,這個代碼將無法通過編譯,因為作為循環(huán)中的一部分而聲明的 i 局部變量的范圍僅限于該循環(huán)體,并且在該循環(huán)之外是不能進(jìn)行訪問的。在缺省情況下,cl 將完成這個代碼的編譯,而不會產(chǎn)生任何錯誤。然而,如果 cl 使用 /Zc:forScope 選項,將導(dǎo)致編譯錯誤。g++ 的行為正好與 cl 相反,對于這個測試將產(chǎn)生下面的錯誤: error: name lookup of 'i' changed for new ISO 'for' scoping
要想禁止這個行為,您可以在編譯期間使用 -fno-for-scope 標(biāo)志。
Visual C++ 和 GNU g++ 都為語言提供了一些非標(biāo)準(zhǔn)的擴(kuò)展。g++ 屬性機(jī)制非常適合于對 Visual C++ 代碼中的平臺特定的特性進(jìn)行移植。屬性語法采用格式 __attribute__ ((attribute-list)),其中屬性列表是以逗號分隔的多個屬性組成的列表。該屬性列表中的單個元素可以是一個單詞,或者是一個單詞后面緊跟使用括號括起來的、該屬性的可能的參數(shù)。這部分研究了如何在移植操作中使用這些屬性。
您可以使用 Visual Studio 中特定的關(guān)鍵字,如 __cdecl、__stdcall 和 __fastcall,以便向編譯器說明函數(shù)的調(diào)用約定。表 1 對有關(guān)的詳細(xì)內(nèi)容進(jìn)行了匯總。
調(diào)用約定 隱含的語義
__cdecl(cl 選項:/Gd) 從右到左地將被調(diào)用函數(shù)的參數(shù)壓入堆棧。在執(zhí)行完畢之后,由調(diào)用函數(shù)將參數(shù)彈出堆棧。
__stdcall(cl 選項:/Gz) 從右到左地將被調(diào)用函數(shù)的參數(shù)壓入堆棧。在執(zhí)行完畢之后,由調(diào)用函數(shù)將參數(shù)彈出堆棧。
__fastcall(cl 選項:/Gr) 將最前面的兩個參數(shù)傳遞到 ECX 和 EDX 寄存器中,同時將所有其他參數(shù)從右到左地壓入堆棧。由被調(diào)用函數(shù)負(fù)責(zé)清除執(zhí)行后的堆棧。
用以表示相同行為的 g++ 屬性是 cdecl、stdcall 和 fastcall。清單 4 顯示了 Windows® 和 UNIX® 中屬性聲明風(fēng)格的細(xì)微差別。
Visual C++ Style Declaration:
double __stdcall compute(double d1, double d2);
g++ Style Declaration:
double __attribute__((stdcall)) compute(double d1, double d2);
/Zpn 結(jié)構(gòu)成員對齊選項可以控制結(jié)構(gòu)在內(nèi)存中的對齊方式。例如,/Zp8 以 8 個字節(jié)為單位對結(jié)構(gòu)進(jìn)行對齊(這也是缺省的方式),而 /Zp16 則以 16 個字節(jié)為單位對結(jié)構(gòu)進(jìn)行對齊。您可以使用 aligned g++ 屬性來指定變量的對齊方式,如清單 5 中所示。
Visual C++ Style Declaration with /Zp8 switch:
struct T1 { int n1; double d1;};
g++ Style Declaration:
struct T1 { int n1; double d1;} __attribute__((aligned(8)));
然而,對齊屬性的有效性將受到固有的連接器局限性的限制。在許多系統(tǒng)中,連接器只能夠以某個最大的對齊方式對變量進(jìn)行對齊。
這個屬性可以告訴編譯器,使用該屬性聲明的函數(shù)以及它調(diào)用的后續(xù)函數(shù)都不會引發(fā)異常。使用這個特性可以對減少整體代碼的大小進(jìn)行優(yōu)化,因為在缺省情況下,即使代碼不會引發(fā)異常,cl 仍然會為 C++ 源代碼生成堆棧展開信息。您可以使用 nothrow g++ 屬性以實現(xiàn)類似的目的,如清單 6 中所示。
Visual C++ Style Declaration:
double __declspec(nothrow) sqrt(double d1);
g++ Style Declaration:
double __attribute__((nothrow)) sqrt(double d1);
一種更加具有可移植性的方法是,使用標(biāo)準(zhǔn)定義的風(fēng)格: double sqrt(double d1) throw ();.
除了前面的一些示例之外,Visual C++ 和 g++ 屬性方案之間還存在一些相似的內(nèi)容。例如,這兩種編譯器都支持 noinline、noreturn、deprecated 和 naked 屬性。
在 Win32 系統(tǒng)中開發(fā)的 C++ 代碼是基于 ILP32 模型的,在該模型中,int、long 和指針類型都是 32 位的。UNIX 系統(tǒng)則遵循 LP64 模型,其中 long 和指針類型都是 64 位的,但是 int 仍然保持為 32 位。大部分的代碼破壞,都是由于這種更改所導(dǎo)致的。這部分簡要討論了您可能會遇到的兩個最基本的問題。從 32 位到 64 位系統(tǒng)的移植是一個非常廣闊的研究領(lǐng)域。有關(guān)這個主題的更多信息,請參見參考資料部分。
某些數(shù)據(jù)類型在 ILP32 和 LP64 模型中是相同的,使用這樣的數(shù)據(jù)類型才是合理的做法。通常,您應(yīng)該盡可能地避免使用 long 和 pointer 數(shù)據(jù)。另外,通常我們會使用 sys/types.h 標(biāo)準(zhǔn) Header 中定義的數(shù)據(jù)類型,但是這個文件中的一些數(shù)據(jù)類型(如 ptrdiff_t, size_t 等等)的大小,在 32 位模型和 64 位模型之間是不一樣的,您在使用時必須小心。
個別數(shù)據(jù)結(jié)構(gòu)的內(nèi)存需求可能會發(fā)生改變,這依賴于編譯器中實現(xiàn)對齊的方式??梢钥紤]清單 7 中的代碼片段。
struct s {
int var1; // hole between var1 and var2
long var2;
int var3; // hole between var3 and ptr1
char* ptr1;
};
// sizeof(s) = 32 bytes
在 LP64 模型中,long 和 pointer 類型都以 64 位為單位進(jìn)行對齊。另外,結(jié)構(gòu)的大小以其中最大成員的大小為單位進(jìn)行對齊。在這個示例中,結(jié)構(gòu) s 以 8 個字節(jié)為單位進(jìn)行對齊,s.var2 變量同樣也是如此。這將導(dǎo)致在該結(jié)構(gòu)中出現(xiàn)一些空白的地方,從而使內(nèi)存膨脹。清單 8 中的重新排列導(dǎo)致該結(jié)構(gòu)的大小變?yōu)?24 個字節(jié)。
struct s {
int var1;
int var3;
long var2;
char* ptr1;
};
// sizeof(s) = 24 bytes
從技術(shù)上講,一個線程是操作系統(tǒng)可以調(diào)度運行的獨立指令流。在這兩種環(huán)境中,線程都位于進(jìn)程之中,并且使用進(jìn)程的資源。只要線程的父進(jìn)程存在,并且 操作系統(tǒng)支持線程,那么線程將具有它自己的獨立控制流。它可能與其他獨立(或者非獨立)使用的線程共享進(jìn)程資源,如果它的父進(jìn)程結(jié)束,那么它也將結(jié)束。下 面對一些典型的應(yīng)用程序接口 (API) 進(jìn)行了概述,您可以使用這些 API 在 Windows 和 UNIX 環(huán)境中建立多線程的項目。對于 WIN32 API,所選擇的接口是 C 運行時例程,考慮到簡單性和清晰性,這些例程符合可移植操作系統(tǒng)接口(Portable Operating System Interface,POSIX)的線程。
請注意:由于本文篇幅有限,我們不可能為編寫多線程應(yīng)用程序的其他方式提供詳細(xì)的介紹。
Windows 使用 C 運行時庫函數(shù)中的 _beginthread API 來創(chuàng)建線程。您還可以使用一些其他的 Win32 API 來創(chuàng)建線程,但是在后續(xù)的內(nèi)容中,您將僅使用 C 運行時庫函數(shù)。顧名思義,_beginthread() 函數(shù)可以創(chuàng)建一個執(zhí)行例程的線程,其中將指向該例程的指針作為第一個參數(shù)。這個例程使用了 __cdecl C 聲明調(diào)用約定,并返回空值。當(dāng)線程從這個例程中返回時,它將會終止。
在 UNIX 中,可以使用 pthread_create() 函數(shù)完成相同的任務(wù)。pthread_create() 子程序使用線程參數(shù)返回新的線程 ID。調(diào)用者可以使用這個線程 ID,以便對該線程執(zhí)行各種操作。檢查這個 ID,以確保該線程存在。
_endthread 函數(shù)可以終止由 _beginthread() 創(chuàng)建的線程。當(dāng)線程的順序執(zhí)行完成時,該線程將自動終止。如果需要在線程中根據(jù)某個條件終止它的執(zhí)行,那么 _endthread() 函數(shù)是非常有用的。
在 UNIX 中,可以使用 pthread_exit() 函數(shù)實現(xiàn)相同的任務(wù)。如果正常的順序執(zhí)行尚未完成,這個函數(shù)將退出線程。如果 main() 在它創(chuàng)建的線程之前完成,并使用 pthread_exit() 退出,那么其他線程將繼續(xù)執(zhí)行。否則,當(dāng) main() 完成的時候,其他線程將自動終止。
要實現(xiàn)同步,您可以使用互斥信號量。在 Windows 中,CreateMutex() 可以創(chuàng)建互斥信號量。它將返回一個句柄,任何需要互斥信號量對象的函數(shù)都可以使用這個句柄,因為對這個互斥信號量提供了所有的訪問權(quán)限。當(dāng)擁有這個互斥信號量的線程不再需要它的時候,可以調(diào)用 ReleaseMutex(),以便將它釋放回系統(tǒng)。如果調(diào)用線程并不擁有這個互斥信號量,那么這個函數(shù)的執(zhí)行將會失敗。
在 UNIX 中,可以使用 pthread_mutex_init() 例程動態(tài)地創(chuàng)建一個互斥信號量。這個方法允許您設(shè)置互斥信號量對象的相關(guān)屬性。或者,當(dāng)通過 pthread_mutex_t 變量聲明它的時候,可以靜態(tài)地創(chuàng)建它。要釋放一個不再需要的互斥信號量對象,可以使用 pthread_mutex_destroy()。
既然您已經(jīng)掌握了本文前面所介紹的內(nèi)容,下面讓我們來看一個小程序示例,該程序使用在主進(jìn)程中執(zhí)行的不同線程向控制臺輸出信息。清單 9 是 multithread.cpp 的源代碼。
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#include <string.h>
#include <conio.h>
#include <process.h>
#else
#include <pthread.h>
#endif
#define MAX_THREADS 32
#ifdef WIN32
void InitWinApp();
void WinThreadFunction( void* );
void ShutDown();
HANDLE mutexObject;
#else
void InitUNIXApp();
void* UNIXThreadFunction( void *argPointer );
pthread_mutex_t mutexObject = PTHREAD_MUTEX_INITIALIZER;
#endif
int threadsStarted; // Number of threads started
int main()
{
#ifdef WIN32
InitWinApp();
#else
InitUNIXApp();
#endif
}
#ifdef WIN32
void InitWinApp()
{
/* Create the mutex and reset thread count. */
mutexObject = CreateMutex( NULL, FALSE, NULL ); /* Cleared */
if(mutexObject == NULL && GetLastError() != ERROR_SUCCESS)
{
printf("failed to obtain a proper mutex for multithreaded application");
exit(1);
}
threadsStarted = 0;
for(;threadsStarted < 5 && threadsStarted < MAX_THREADS;
threadsStarted++)
{
_beginthread( WinThreadFunction, 0, &threadsStarted );
}
ShutDown();
CloseHandle( mutexObject );
getchar();
}
void ShutDown()
{
while ( threadsStarted > 0 )
{
ReleaseMutex( mutexObject ); /* Tell thread to die. */
threadsStarted--;
}
}
void WinThreadFunction( void *argPointer )
{
WaitForSingleObject( mutexObject, INFINITE );
printf("We are inside a thread\n");
ReleaseMutex(mutexObject);
}
#else
void InitUNIXApp()
{
int count = 0, rc;
pthread_t threads[5];
/* Create independent threads each of which will execute functionC */
while(count < 5)
{
rc = pthread_create(&threads[count], NULL, &UNIXThreadFunction, NULL);
if(rc)
{
printf("thread creation failed");
exit(1);
}
count++;
}
// We will have to wait for the threads to finish execution otherwise
// terminating the main program will terminate all the threads it spawned
for(;count >= 0;count--)
{
pthread_join( threads[count], NULL);
}
//Note : To destroy a thread explicitly pthread_exit() function can be used
//but since the thread gets terminated automatically on execution we did
//not make explicit calls to pthread_exit();
exit(0);
}
void* UNIXThreadFunction( void *argPointer )
{
pthread_mutex_lock( &mutexObject );
printf("We are inside a thread\n");
pthread_mutex_unlock( &mutexObject );
}
#endif
我們利用 Visual Studio Toolkit 2003 和 Microsoft Windows 2000 Service Pack 4 通過下面的命令行對 multithread.cpp 的源代碼進(jìn)行了測試:
cl multithread.cpp /DWIN32 /DMT /TP
我們還在使用 g++ 編譯器版本 3.4.4 的 UNIX 平臺中通過下面的命令行對它進(jìn)行了測試:
g++ multithread.cpp -DUNIX -lpthread
清單 10 是該程序在兩種環(huán)境中的輸出。
We are inside a thread
We are inside a thread
We are inside a thread
We are inside a thread
We are inside a thread
在兩種完全不同的平臺(如 Windows 和 UNIX)之間進(jìn)行移植,需要了解多個領(lǐng)域的知識,包括了解編譯器和它們的選項、平臺特定的特性(如 DLL)以及實現(xiàn)特定的特性(如線程)。本系列文章介紹了移植工作的眾多方面。有關(guān)這個主題的更深入信息,請參見參考資料部分。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
多線程下 ,linux和 windows開發(fā)應(yīng)注意的區(qū)別 - jamesf1982的專欄 ...
VC/MFC調(diào)試技術(shù)(轉(zhuǎn)) - carekee - 博客園
線程中的while循環(huán)占用CPU太高的問題
malloc是否是線程安全的?
Android Native 內(nèi)存泄漏系統(tǒng)化解決方案
pthread_testcancel
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服