2012年9月26日
#
在使用不同編程語言進行軟件聯合開發的時候,需要統一函數、變量、數據類型、常量等鏈接規范,特別是在不同模塊之間共享的接口部分,當開發程序庫的時候,明確鏈接規范也是必須遵循的一條規則。
對COM接口及其使用的數據類型來說,是否采用統一的鏈接規范,對其二進制兼容性和可移植性都沒有影響。因為連接規范主要影響到名字改編方案的不同,這樣即使接口兩端對接口本身的解釋不通,只要它們使用一致的成員對齊方式和布局方案、一致的函數調用規范、一致virtual function實現方式,總是就是一致的C++對象模型。并且保證COM組件升級時不改變原來的接口和數據類型定義,則所有方法的運行時綁定都不會存在問題(所有方法的調試都被轉換為通過對象指針對vptr和vtable及函數指針的操作,這種間接性不再需要任何方法名即函數名的參與,而接口名和方法名只是為了讓客戶端的代碼能夠順利通過編譯,但是連接時就完全不在需要了。)
但是對于定義于普通靜態鏈接庫和動態鏈接庫中的全局數據類型、全局函數、全局變量甚至全局常量,它們的連接規范必須在兩端保持一致、否則客戶程序會出現連接問題。這是因為普通的封裝為DLL的函數庫或者類庫,客戶程序在創建使一般都需要與它們的導出庫進行連接,除非使用loadlibrary()和getprocaddress()函數對來獲得DLL中函數的地址,通用的連接規范要屬C連接規范:extern‘C’。
具體使用方法,里仁教育嵌入式培訓職業講師詳情講解:
Extern’C’void WinMainCRTStartup();
Extern’C’const CLSID CLSID_DataConvert();
Extern’C’struct Student{.......};
Extern’C’student g_student;
如果是對一段代碼指定連接規范:
#ifdef _cplusplus
Extern ‘C’{
#endif
Const int MAX_AGE=200;
#pragma pack(push,4)
Typedef struct _person
{
Char *m_Name;
Int m_Age;
}person,*personPtr;
#pragma pack(pop)
Person g_Me;
Int _cdecl memcmp(const void*,const void*,size_t);
Void * _cdecl memcpy(void,const void*,size_t);
Void* _cdecl memset(void*,int,size_t);
#ifdef _cplusplus
}
#endif
嵌入式行業資訊:全套基礎:
http://www.lirenedu.org/index.php?ack=lanmu&id=82
2012年9月18日
#
有些進程在運行時會占用大量的CPU,有些進程會導致X死掉,有些進程會吞噬掉大量的內存,這些進程直接影響了用戶的正常工作,最直接的現象就是系統運行緩慢,死機等現象,處理這些進程一般的方法就是結束這個進程,就是所說的把它KILL掉。下面介紹幾種消滅進程的方法。
l 使用Kill命令來消滅進程
如果運行了某個程序導致了死機,那么就應該切換到其他的控制臺下,按下ctrl+alt+fx,其中x可以是1·5,這取決于用戶的try的多少。
用ps顯示這個程序的進程ID。
這里以xchat為例。
$ps aux |grep xchat
Wanglin 12063 0.0 1.8 89536 19028 ?S1 apr06 2:40 xchat
其中12063就是它的ID。
也可以使用pgrep來顯示ID,如下:
$pgrep xchar
12063
使用Kill來消滅這個進程
使用kil來消滅進程,如果消滅不掉,還要加參數-9,它可以強制結束進程。
$ kill 12063
$ kill -9 12063
l 使用pkill或者killall來消滅進程
它們的共同點就是都可以用程序的名稱作為參數。
$ pkill -9 xchat
$ killall xchat
l 使用圖形化的方式來消滅進程
$xkill
會出現一個X形的光標,單擊需要消滅的窗口,就可以消滅這個程序。www.lirenedu.org
Patch的主要用途就是更新源代碼到新的版本,避免下載整個源代碼,下載一個有效的補丁僅僅需要下載發生變化的那些代碼行就可以了,patch的幫助文檔中羅列了眾多的用法,其實大多數的時間只要下面兩個命令參數就能滿足大家的需要。下面講解patch的用法,以Ubuntu7.10系統為例。
1. 命令格式
#patch -p1<[patchfile]
或者
#patch -R <[patchfile]
上面兩個格式任選一條就可以了。
2.使用方法
#patch -p1<[patchfile]
要求補丁文件要放到源代碼目錄下,然后在運行這條命令。
例如:給xchat2.6.0打補丁, 補丁文件是xc260-fetext.diff。
首先選入 xchat2.6.0的目錄, 并且將xc260-fix-fetext.diff文件復制到這個目錄,然后運行:
#patch -p1<xc260-fix-fetext.diff
如果出現提示信息:patching file src/text/fe-text/fe-text.c 這說明打補丁成功了。
#patch -R<[pathfile]
這個命令運行后,還要指定被補丁的文件的路徑和文件名.www.lirenedu.org
2012年9月12日
#
在Ubuntu系統下工作,只掌握圖形化的配置工具還是不夠的,系統在出現故障的時候往往使用的是終端的操作模式,下面里仁3G培訓講師介紹在終端下如何配置網絡。
臨時改變網絡參數
l .Ifconfig:查看和配置IP地址。
$ifconfig eth0
$sudo ifconfig eth0 192.168.9.23 netmask 255.255.255.0
route:配置路由參數
$sudo route add default gw 192.168.9.1 eth0 #設置默認網關
使參數立即生效
$sudo/etc/init.d/networking restart
修改網絡配置文件
設置DNS服務器。
$sudo echo‘nameserver=219.150.32.132>/etc/resolv.conf’
編輯/etc/network/interfaces。
$sudo vim /etc/network/interfaces
Auto lo
Iface lo inet loopback
Iface eth0 inet static #設置eth0,靜態IP
Address 192.168.8.45
Netmask 255.255.255.0
Gateway 192.168.8.1
Iface eht1inet dhcp #設置eth1為dhcp模式
l 可以通過下面的命令設置路由。
Up route add default gw 192.168.8.1 eth1
Up route add –net 192.168.8.0/24 gw 192.168.8.1 eth0
Down route del –net 192.168.8.0/24 gw 192.168.8.1 eth0
其中,當網絡接口up時,執行它后面的命令;當網絡接口down時,執行它后面的命令。
使用參數立即生效。
$sudo /etc/init.d/networking restart 轉:www.lirenedu.org
許多學員都使用linux來完成各種工作,包括學習、辦公、編程、網絡維護等,但對所使用系統的一些基本信息知了甚少,有的連自己顯卡的型號、CPU的具體型號、硬盤的使用情況、內存的使用情況網絡的使用情況都不清楚,一旦系統出現故障,就無從下手,所以在此里仁3G嵌入式培訓講師有必要給大家介紹如何準確地獲得自己的系統信息。
1. 系統信息
l 查看內核信息。 $uname -a
l 查看操作系統的版本。 $head –n 1/etc/issue
l 查看CPU的信息。 $cat /proc/cpuinfo
l 查看計算機名稱。 $hostname
l 列出所有PCI設備信息。 $lspci –tv
l 列出所有USB設備信息。 $lsusb –tv
l 列出系統加載的模塊信息。 $lsmod
2. 系統資源的使用信息。
l 查看內存和交換區分的使用量。 $free –m
l 查看硬盤分區的使用情況。 $df –h
l 查看某個目錄的大小。 $du –sh<目錄>
l 查看內存總量和空閑內存量。
$grep memTotal /proc/meminfo
$grep memfree /proc/meminfo
l 查看系統運行時間、用戶數和負載。$uptime
l 查看系統負載。$cat /proc/loadavg www.lirenedu.org
2012年9月3日
#
編譯器無法預期一個程序在執行過程中會在何時創建一些什么對象,而只能根據當時的上下文要求創建,對象的初始化最好能夠通過運行時執行一個函數來完成,而且是在對象創建的同時,這個函數就是構造函數,同樣,對象在完成其使命的時候能夠通過一個函數來銷毀,這就是析構函數。
當給一個對象分配好原始內存空間的時候,這個對象就應該算創建起來了。只不過它還處于一種“原始狀態”,即末初始化的,不良的狀態,如果把這樣的內存直接拿來使用,除非第一個操作是賦值,否則極有可能出錯。例如:
Long long1; //局部變量
Count<
Char*pstr=(char*)malloc(1024);
Cout<
因此,創建一個變量或動態對象時一定不要忘記初始化。 初始化就是在對象創建的同時使用初值直接填充對象的內存單元,因此,不會有數據類型轉換等中間過程,也就不會產生臨時對象,而賦值則是在對象創建好后任何時候都可以調用的而且可以多次調用的函數,由于它調用的是“=”運算符,因此可能需要進行類型轉換,即會產生臨時對象。
C++對象可以使用構造函數來初始化,構造函數是任何對象創建時自動調用的第一個成員函數,也是為每個對象僅調用一次的成員函數,所以構造函數的作用就是:當對象的內存分配好后把它原始狀態變成良好的可用的狀態。
有的程序員可能認為:雖然我沒有在構造函數中初始化數據成員,但是我在聲明一個對象后馬上調用它的set-XXX()函數來初始化它的每一個成員,效果也是一樣的。
最好為每個類顯式地定義構造函數和析構函數,即使它們暫時空著,尤其是當類含有指針成員或引用成員的時候。
構造函數的另一重要用途就是給一些可能可能存在的隱含成員如vptr創造一個初始化的機會,否則虛擬機將不能保證實現,每當此時,如果程序員沒有為一個多態類顯式地定義默認構造函數、拷貝構造函數、析構函數或拷貝賦值函數,那么編譯器會自動得生成相應的函數,它們都是public inline的,并在其中插入正確初始化或修改vptr數據成員值的代碼,而且確保基類對象和派生類對象構造時及在它們之間拷貝時vptr能夠指向或重新指向恰當的vtable,這樣的4個函數分布叫非平凡默認構造函數、非平凡拷貝構造函數、非平凡析構函數和非平凡拷貝賦值函數。www.lirenedu.org
與函數堆棧使用密切相關的就是函數調用規范,即調用約定(Calling Convenion)。函數調用規范決定了函數調用的實參壓棧、退棧及堆棧釋放的方式以及函數名改編的方案,windows環境下常用的調用規范有:
1) _cedcl:這是C++/C函數的默認調用規范,參數從右向左傳遞壓入堆棧,由調用函數復雜堆棧的清退,因此這種方式利于傳遞個數可變的參數給被調用函數。如printf()就是這樣的函數。
2) _stdcall:這是Win API函數使用的調用規范,參數從右向左依次傳遞并壓入堆棧,由被調用函數復雜堆棧的清退。該規范生成的函數代碼比_cdecl更小,但當函數有可變個數的參數時會轉為_cdecl規范。在Windows中,宏WINAPI、CALLBACK都定義為_stdcall。
3) _thiscall:是C++非靜態成員函數的默認調用規范,不能使用個數可變的參數。當調用非靜態成員函數的時候,this指針直接保存在ECX寄存器中而壓入函數堆棧,其他方面與_stdcall相同。
4) _fastcall:該規范所修飾的函數的實參將被直接傳遞到CPU寄存器中而不是內存堆棧中,堆棧清退由被調用函數負責,該規范不能用于成員函數。
函數必須制定的一個調用規范,特別是在模塊之間的邏輯接口中,每個函數原型的調用規范必須與其實的調用規范保持一致,否則會出現編譯連接錯誤。如果你調用了在某個DLL中實現的COM對象的方法,而這些方法在創建時卻沒顯式地制定調用規范,那么它們會使用環境默認的調用規范,雖然你的程序可以通過編譯和連接,但是在運行時就可能導致程序崩潰。
所以,凡是接口函數都必須顯式地制定其調用規范,除非接口函數是類的非靜態成員函數,如果不顯式制定調用規范,類的靜態成員函數和全局函數將采用C++/C默認的函數調用規范或者由工程設置指定的調用規范,因此最好也為靜態成員函數顯式地指定調用規范。
注意:類的靜態成員函數的默認調用規范不是thiscall,類的友元函數的調用也不是thiscall,它們都是由函數本身指定或者由工程設定的。COM接口的方法都指定_stdcall調用規范,而我們自己開發COM對象及接口時也可以指定其他的調用規范。
一定要知道C基礎的基本概念:
認識函數堆棧:http://www.lirenedu.org/index.php?ack=xinwen&id=1026
基于C語言基礎概念:http://www.lirenedu.org/index.php?ack=xinwen&id=1024
操作系統幾個基本要點:http://www.lirenedu.org/index.php?ack=xinwen&id=1029
2012年8月27日
#
一、可默認構造的,也即具有public的default constructor,不論是用戶顯式定義還是編譯器默認的,但是用戶定義的帶參數constructor會仰制編譯器合成default constructor,實際上并非任何情況下任意一種容器要求其元素類型滿足這一條件,特別是關聯式容器,因為只有序列式容器的某些函數才可能明確地或隱含地使用元素類型的default constructor,如果你不調用這樣的成員函數,編譯器就不需要元素類型的默認構造函數。
二、可拷貝構造和拷貝賦值的,既具有public的copy constructor和copy assignment operator,不論是編譯器默認還是operator,如果沒有顯式定義它的話,這個條件可歸結為:元素必須是拷貝的,但實際上拷貝賦值的要求也不是強制的,原因和default constructor類似。
三、具有public的destructor,不論是編譯器默認的還是用戶顯式定義的。
四、對于關聯式容器,要求其元素必須是可比較的。
Auto_ptr滿足上述條件嗎?至少滿足前三條,因此至少可以作為序列式容器的元素,如果為auto-ptr定義了比較運算符的話,應該還可以把它作為關聯式容器的元素。
但是auto_ptr的特點是接管和轉移擁有權,而不是像原始指針那樣可以共享實值對象,即auto_ptr在初始化時接管實值對象和擁有權,而在拷貝時會交出實值對象及其擁有權。
因此,auto_ptr對象和它的拷貝不會共享實值它的拷貝并不相同,然而根據STL容器值語義的要求,可拷貝構造意味著一個著把一個對象賦值給另一個同類型對象將產生兩個相同的對象,顯然,auto_ptr不能滿足這一要求,與上面結論矛盾!那么問題出在哪里呢?
在揭開auto_ptr的之前需要了解copy constructor和copy assignment operator,的幾種合法形式,任何一個類都允許兩種形式的copy constructor:
C(const C©);
C(C©);
同樣,copy assignment operator允許類似的兩種形式。
C& operator=(const C ©);
C& operator=(C & copy);
實際上,由于copy assignment operator為普通的運算符重載成員函數,因此還可以定義下列形式賦值函數;
C&operator=(C copy);
如果要防止用戶把一些不合適的對象放入容器中,就要求對象的設計和是實現者使用一些語言支持但不常用的特征,也就是說,要能夠在編譯階段就阻止這種具有潛在危險性的行為,常用的方法就是迫使其違反C++靜態類型安全規則。
源處:
http://www.lirenedu.org/index.php?ack=xinwen&id=1178
2012年8月23日
#
傳統的錯誤處理是用不同的數值來表示不同類型的錯誤,其表達能力很有限,因為一個數字包含的信息量太少,而C++異常處理機制將異常類型化,顯然一個類型要比一個數字包含的信息量大得多。
比如我們常用的函數fopen(),當打開文件失敗是返回NULL,按照傳統的錯誤處理方法,在調用Fopen()后立即檢查其返回值,如果為NULL就進行錯誤處理,如果將返回NULL改為拋出異常OpenFailed,那么我們就不用在調用fopen()后馬上檢查返回值,而是在調用函數內部或者更高層的調用者那里設置異常處理器來捕獲這個異常,C++保證:如果一個異常在拋出點沒有得到處理,那么它將一直拋向上層調用者,直至main()函數,直到找到一個類型匹配的異常處理器,否則調用terminate()結束程序。
可以看出:異常處理機制實際上是一種運行時通知機制。
Class DevidedByZero{};
Double Devide(double a,double b)
{
If(abs(b)::numeric_limits::epsilon())
{
Throw DevidedByZero();//提前檢測異常發生條件并拋出自定義異常
Return a/b; //這才是可能真正發出錯誤的地方
}
Void test()
{
Double x=100,y=20.5
Try{
Cout<拋出異常DevidedByZero
}
Catch(DevidedByZero&){
Cerr<< “ Devided by zero!”<
}
}
2012年8月21日
#
如果在申請動態內存時找不到足夠大的連續字節內存塊,malloc()和new()會使用不同的方式宣告內存申請失敗,通常有如下幾種方式處理“內存耗盡”問題:
1. 判斷指針是否為NULL,如果是則立刻用return語句終止本函數。例如:
Void Func(void)
{
A *a=new(nothrow) A;
If(a==NULL)return;
……
}
2. 判斷指針是否為NULL,如果是則立刻用exit(1)終止整個程序的運行,例如:
Void Func(void)
{
A *a=new(nothrow) A;
If(a==NULL)exit(1);
}
3. 為new和malloc()預設異常處理函數,例如,Visual C++可以用_set_new_hander函數為new設置用戶自定義異常處理函數,也可以讓malloc()享用與new相同的異常處理函數。
4. 捕獲new拋出的異常,并嘗試從中恢復。
上述(1)和(2)兩種方式使用最普通。如果一個函數內有多處需要動態申請內存,那么方式(1)就顯得力不從心,應該用方式(2)來處理。不過在C++中我們提倡使用方式(4)。
有一個很重要的現象要告訴大家:
對于32位以上的應用程序而言,一般情況下使用malloc()和new幾乎不可能導致‘內存耗盡’。我在windows98下用Visual C++編寫了測試程序:
這個程序無休地運行下去,根本不會終止,因為32位操作系統支持‘虛存’,內存用完了,自動用硬件空間頂替。
Void main()
{
Int *p=NULL;
Unsigned int len=1024*1024;
While(1){
P=new(nothrow) int[len]; //或者 malloc(sizeof(int)*len);
If(!p){
Len>>=1; //len縮小一半
If(len==0)
Exit(1);
Continue;
}
Cout<<“Allocated:”<<“(len*sizeof(int))”<<“bytes.”<<endl;
}
}
可以得出一個結論:
對于32位以上應用程序,內存耗盡錯誤處理程序幾乎毫無用處,但是必須強調不加錯誤處理將導致程序的質量很差,千萬不可因小失大。